]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Added AliAnalysisAlien::AddIncludePath() to be able to add include paths for runtime...
[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                   fRunNumbers(),
52                   fExecutable(),
53                   fArguments(),
54                   fAnalysisMacro(),
55                   fAnalysisSource(),
56                   fAdditionalLibs(),
57                   fSplitMode(),
58                   fAPIVersion(),
59                   fROOTVersion(),
60                   fAliROOTVersion(),
61                   fUser(),
62                   fGridWorkingDir(),
63                   fGridDataDir(),
64                   fDataPattern(),
65                   fGridOutputDir(),
66                   fOutputArchive(),
67                   fOutputFiles(),
68                   fInputFormat(),
69                   fDatasetName(),
70                   fJDLName(),
71                             fMergeExcludes(),
72                   fIncludePath(),
73                   fCloseSE(),
74                   fInputFiles(0),
75                   fPackages(0)
76 {
77 // Dummy ctor.
78    SetDefaults();
79 }
80
81 //______________________________________________________________________________
82 AliAnalysisAlien::AliAnalysisAlien(const char *name)
83                  :AliAnalysisGrid(name),
84                   fGridJDL(NULL),
85                   fPrice(0),
86                   fTTL(0),
87                   fSplitMaxInputFileNumber(0),
88                   fMaxInitFailed(0),
89                   fMasterResubmitThreshold(0),
90                   fNtestFiles(0),
91                   fRunNumbers(),
92                   fExecutable(),
93                   fArguments(),
94                   fAnalysisMacro(),
95                   fAnalysisSource(),
96                   fAdditionalLibs(),
97                   fSplitMode(),
98                   fAPIVersion(),
99                   fROOTVersion(),
100                   fAliROOTVersion(),
101                   fUser(),
102                   fGridWorkingDir(),
103                   fGridDataDir(),
104                   fDataPattern(),
105                   fGridOutputDir(),
106                   fOutputArchive(),
107                   fOutputFiles(),
108                   fInputFormat(),
109                   fDatasetName(),
110                   fJDLName(),
111                   fMergeExcludes(),
112                   fIncludePath(),
113                   fCloseSE(),
114                   fInputFiles(0),
115                   fPackages(0)
116 {
117 // Default ctor.
118    SetDefaults();
119 }
120
121 //______________________________________________________________________________
122 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
123                  :AliAnalysisGrid(other),
124                   fGridJDL(NULL),
125                   fPrice(other.fPrice),
126                   fTTL(other.fTTL),
127                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
128                   fMaxInitFailed(other.fMaxInitFailed),
129                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
130                   fNtestFiles(other.fNtestFiles),
131                   fRunNumbers(other.fRunNumbers),
132                   fExecutable(other.fExecutable),
133                   fArguments(other.fArguments),
134                   fAnalysisMacro(other.fAnalysisMacro),
135                   fAnalysisSource(other.fAnalysisSource),
136                   fAdditionalLibs(other.fAdditionalLibs),
137                   fSplitMode(other.fSplitMode),
138                   fAPIVersion(other.fAPIVersion),
139                   fROOTVersion(other.fROOTVersion),
140                   fAliROOTVersion(other.fAliROOTVersion),
141                   fUser(other.fUser),
142                   fGridWorkingDir(other.fGridWorkingDir),
143                   fGridDataDir(other.fGridDataDir),
144                   fDataPattern(other.fDataPattern),
145                   fGridOutputDir(other.fGridOutputDir),
146                   fOutputArchive(other.fOutputArchive),
147                   fOutputFiles(other.fOutputFiles),
148                   fInputFormat(other.fInputFormat),
149                   fDatasetName(other.fDatasetName),
150                   fJDLName(other.fJDLName),
151                   fMergeExcludes(other.fMergeExcludes),
152                   fIncludePath(other.fIncludePath),
153                   fCloseSE(other.fCloseSE),
154                   fInputFiles(0),
155                   fPackages(0)
156 {
157 // Copy ctor.
158    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
159    if (other.fInputFiles) {
160       fInputFiles = new TObjArray();
161       TIter next(other.fInputFiles);
162       TObject *obj;
163       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
164       fInputFiles->SetOwner();
165    }   
166    if (other.fPackages) {
167       fPackages = new TObjArray();
168       TIter next(other.fPackages);
169       TObject *obj;
170       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
171       fPackages->SetOwner();
172    }   
173 }
174
175 //______________________________________________________________________________
176 AliAnalysisAlien::~AliAnalysisAlien()
177 {
178 // Destructor.
179    if (fGridJDL) delete fGridJDL;
180    if (fInputFiles) delete fInputFiles;
181    if (fPackages) delete fPackages;
182 }   
183
184 //______________________________________________________________________________
185 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
186 {
187 // Assignment.
188    if (this != &other) {
189       AliAnalysisGrid::operator=(other);
190       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
191       fPrice                   = other.fPrice;
192       fTTL                     = other.fTTL;
193       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
194       fMaxInitFailed           = other.fMaxInitFailed;
195       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
196       fNtestFiles              = other.fNtestFiles;
197       fRunNumbers              = other.fRunNumbers;
198       fExecutable              = other.fExecutable;
199       fArguments               = other.fArguments;
200       fAnalysisMacro           = other.fAnalysisMacro;
201       fAnalysisSource          = other.fAnalysisSource;
202       fAdditionalLibs          = other.fAdditionalLibs;
203       fSplitMode               = other.fSplitMode;
204       fAPIVersion              = other.fAPIVersion;
205       fROOTVersion             = other.fROOTVersion;
206       fAliROOTVersion          = other.fAliROOTVersion;
207       fUser                    = other.fUser;
208       fGridWorkingDir          = other.fGridWorkingDir;
209       fGridDataDir             = other.fGridDataDir;
210       fDataPattern             = other.fDataPattern;
211       fGridOutputDir           = other.fGridOutputDir;
212       fOutputArchive           = other.fOutputArchive;
213       fOutputFiles             = other.fOutputFiles;
214       fInputFormat             = other.fInputFormat;
215       fDatasetName             = other.fDatasetName;
216       fJDLName                 = other.fJDLName;
217       fMergeExcludes           = other.fMergeExcludes;
218       fIncludePath             = other.fIncludePath;
219       fCloseSE                 = other.fCloseSE;
220       if (other.fInputFiles) {
221          fInputFiles = new TObjArray();
222          TIter next(other.fInputFiles);
223          TObject *obj;
224          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
225          fInputFiles->SetOwner();
226       }   
227       if (other.fPackages) {
228          fPackages = new TObjArray();
229          TIter next(other.fPackages);
230          TObject *obj;
231          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
232          fPackages->SetOwner();
233       }   
234    }
235    return *this;
236 }
237
238 //______________________________________________________________________________
239 void AliAnalysisAlien::AddIncludePath(const char *path)
240 {
241 // Add include path in the remote analysis macro.
242    TString p(path);
243    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
244    else                  fIncludePath += Form("-I%s ", path);
245 }
246
247 //______________________________________________________________________________
248 void AliAnalysisAlien::AddRunNumber(Int_t run)
249 {
250 // Add a run number to the list of runs to be processed.
251    if (fRunNumbers.Length()) fRunNumbers += " ";
252    fRunNumbers += Form("%d", run);
253 }   
254
255 //______________________________________________________________________________
256 void AliAnalysisAlien::AddDataFile(const char *lfn)
257 {
258 // Adds a data file to the input to be analysed. The file should be a valid LFN
259 // or point to an existing file in the alien workdir.
260    if (!fInputFiles) fInputFiles = new TObjArray();
261    fInputFiles->Add(new TObjString(lfn));
262 }
263    
264 //______________________________________________________________________________
265 Bool_t AliAnalysisAlien::Connect()
266 {
267 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
268    if (gGrid && gGrid->IsConnected()) return kTRUE;
269    if (!gSystem->Getenv("alien_API_USER")) {
270       Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
271             gSystem->Getenv("UID"));
272       return kFALSE;
273    }         
274    if (!gGrid) {
275       Info("Connect", "Trying to connect to AliEn ...");
276       TGrid::Connect("alien://");
277    }
278    if (!gGrid || !gGrid->IsConnected()) {
279       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
280       return kFALSE;
281    }  
282    fUser = gGrid->GetUser();
283    fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
284    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
285    return kTRUE;
286 }
287
288 //______________________________________________________________________________
289 void AliAnalysisAlien::CdWork()
290 {
291 // Check validity of alien workspace. Create directory if possible.
292    if (!Connect()) {
293       Error("CdWork", "Alien connection required");
294       return;
295    } 
296    TString homedir = gGrid->GetHomeDirectory();
297    TString workdir = homedir + fGridWorkingDir;
298    if (!gGrid->Cd(workdir)) {
299       gGrid->Cd(homedir);
300       if (gGrid->Mkdir(workdir)) {
301          gGrid->Cd(fGridWorkingDir);
302          Info("CreateJDL", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
303       } else {
304          Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
305                  workdir.Data(), homedir.Data());
306          fGridWorkingDir = "";
307       }          
308    }      
309 }
310
311 //______________________________________________________________________________
312 Bool_t AliAnalysisAlien::CheckInputData()
313 {
314 // Check validity of input data. If necessary, create xml files.
315    if (!fInputFiles && !fRunNumbers.Length()) {
316        Error("CheckInputData", "You have to specify either a set of run numbers or some existing grid files. Use AddRunNumber()/AddDataFile().");
317       return kFALSE;
318    }
319    // Process declared files
320    Bool_t is_collection = kFALSE;
321    Bool_t is_xml = kFALSE;
322    Bool_t use_tags = kFALSE;
323    Bool_t checked = kFALSE;
324    CdWork();
325    TString file;
326    TString workdir = gGrid->GetHomeDirectory();
327    workdir += fGridWorkingDir;
328    if (fInputFiles) {
329       TObjString *objstr;
330       TIter next(fInputFiles);
331       while ((objstr=(TObjString*)next())) {
332          file = workdir;
333          file += "/";
334          file += objstr->GetString();
335          // Store full lfn path
336          if (FileExists(file)) objstr->SetString(file);
337          else {
338             file = objstr->GetName();
339             if (!FileExists(objstr->GetName())) {
340                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
341                      objstr->GetName(), workdir.Data());
342                return kFALSE;
343             }         
344          }
345          Bool_t iscoll, isxml, usetags;
346          CheckDataType(file, iscoll, isxml, usetags);
347          if (!checked) {
348             checked = kTRUE;
349             is_collection = iscoll;
350             is_xml = isxml;
351             use_tags = usetags;
352             TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
353          } else {
354             if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
355                Error("CheckInputData", "Some conflict was found in the types of inputs");
356                return kFALSE;
357             } 
358          }
359       }
360    }
361    // Process requested run numbers
362    if (!fRunNumbers.Length()) return kTRUE;
363    // Check validity of alien data directory
364    if (!fGridDataDir.Length()) {
365       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
366       return kFALSE;
367    }
368    if (!gGrid->Cd(fGridDataDir)) {
369       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
370       return kFALSE;
371    }
372    if (is_collection) {
373       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
374       return kFALSE;   
375    }
376    
377    if (checked && !is_xml) {
378       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
379       return kFALSE;   
380    }
381    // Check validity of run number(s)
382    TObjArray *arr;
383    TObjString *os;
384    TString path;
385    if (!checked) {
386       checked = kTRUE;
387       use_tags = fDataPattern.Contains("tag");
388       TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
389    }   
390    if (use_tags != fDataPattern.Contains("tag")) {
391       Error("CheckInputData", "Cannot mix input files using/not using tags");
392       return kFALSE;
393    }
394    if (fRunNumbers.Length()) {
395       arr = fRunNumbers.Tokenize(" ");
396       TIter next(arr);
397       while ((os=(TObjString*)next())) {
398          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
399          if (!gGrid->Cd(path)) {
400             Error("CheckInputData", "Run number %s not found in path: %s", os->GetString().Data(), path.Data());
401             return kFALSE;
402          }
403          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
404          TString msg = "\n#####   file: ";
405          msg += path;
406          msg += " type: xml_collection;";
407          if (use_tags) msg += " using_tags: Yes";
408          else          msg += " using_tags: No";
409          Info("CheckDataType", msg.Data());
410          AddDataFile(path);
411       }
412       delete arr;   
413    }
414    return kTRUE;      
415 }   
416
417 //______________________________________________________________________________
418 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
419 {
420 // Create dataset for the grid data directory + run number.
421    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
422    if (!Connect()) {
423       Error("CreateDataset", "Cannot create dataset with no grid connection");
424       return kFALSE;
425    }   
426
427    // Cd workspace
428    CdWork();
429    TString workdir = gGrid->GetHomeDirectory();
430    workdir += fGridWorkingDir;
431
432    // Compose the 'find' command arguments
433    TString command;
434    TString options = "-x collection ";
435    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
436    TString conditions = "";
437    
438    TString file;
439    TString path;
440    if (!fRunNumbers.Length()) return kTRUE;   
441    // Several runs
442    TObjArray *arr = fRunNumbers.Tokenize(" ");
443    TObjString *os;
444    TIter next(arr);
445    while ((os=(TObjString*)next())) {
446       path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
447       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
448       else file = Form("%s.xml", os->GetString().Data());
449       if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
450          Info("CreateDataset", "\n#####   Removing previous dataset %s", file.Data());
451          gGrid->Rm(file); 
452       }
453       command = "find ";
454       command += options;
455       command += path;
456       command += pattern;
457 //      conditions = Form(" > %s", file.Data());
458       command += conditions;
459       TGridResult *res = gGrid->Command(command);
460       if (res) delete res;
461       // Write standard output to file
462       gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
463       if (TestBit(AliAnalysisGrid::kTest)) break;
464       // Copy xml file to alien space
465       TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
466       if (!FileExists(file)) {
467          Error("CreateDataset", "Command %s did NOT succeed", command.Data());
468          delete arr;
469          return kFALSE;
470       }
471    }   
472    delete arr;
473    return kTRUE;
474 }
475
476 //______________________________________________________________________________
477 Bool_t AliAnalysisAlien::CreateJDL()
478 {
479 // Generate a JDL file according to current settings. The name of the file is 
480 // specified by fJDLName.
481    Bool_t error = kFALSE;
482    TObjArray *arr = 0;
483    Bool_t copy = kTRUE;
484    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
485    Bool_t generate = kTRUE;
486    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
487    if (!Connect()) {
488       Error("CreateJDL", "Alien connection required");
489       return kFALSE;
490    }   
491    // Check validity of alien workspace
492    CdWork();
493    TString workdir = gGrid->GetHomeDirectory();
494    workdir += fGridWorkingDir;
495    if (generate) {
496       TObjString *os;
497       if (!fInputFiles) {
498          Error("CreateJDL()", "Define some input files for your analysis.");
499          error = kTRUE;
500       }
501       // Compose list of input files   
502       // Check if output files were defined
503       if (!fOutputFiles.Length()) {
504          Error("CreateJDL", "You must define at least one output file");
505          error = kTRUE;
506       }   
507       // Check if an output directory was defined and valid
508       if (!fGridOutputDir.Length()) {
509          Error("CreateJDL", "You must define AliEn output directory");
510          error = kTRUE;
511       } else {
512          if (!gGrid->Cd(fGridOutputDir)) {
513             if (gGrid->Mkdir(fGridOutputDir)) {
514                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
515             } else {
516                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
517                error = kTRUE;
518             }
519          }
520          gGrid->Cd(workdir);
521       }   
522       // Exit if any error up to now
523       if (error) return kFALSE;   
524       // Set JDL fields
525       fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
526       fGridJDL->SetExecutable(fExecutable);
527 //      fGridJDL->SetTTL((UInt_t)fTTL);
528       fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
529       if (fMaxInitFailed > 0) 
530          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
531       if (fSplitMaxInputFileNumber > 0) 
532          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
533       if (fSplitMode.Length()) 
534          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
535 //      fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
536       if (fAliROOTVersion.Length())  
537          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
538       if (fROOTVersion.Length()) 
539          fGridJDL->AddToPackages("ROOT", fROOTVersion);
540       if (fAPIVersion.Length()) 
541          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
542       fGridJDL->SetInputDataListFormat(fInputFormat);
543       fGridJDL->SetInputDataList("wn.xml");
544       if (fInputFiles) {
545          TIter next(fInputFiles);
546          while ((os=(TObjString*)next()))
547             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
548       }      
549       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
550       fGridJDL->AddToInputSandbox(Form("LF:%s/analysis.root", workdir.Data()));
551       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
552          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
553       if (fAdditionalLibs.Length()) {
554          arr = fAdditionalLibs.Tokenize(" ");
555          TIter next(arr);
556          while ((os=(TObjString*)next())) {
557             if (os->GetString().Contains(".so")) continue;
558             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
559          }   
560          delete arr;   
561       }
562       if (fPackages) {
563          TIter next(fPackages);
564          TObject *obj;
565          while ((obj=next()))
566             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
567       }
568       if (fOutputArchive.Length()) {
569          arr = fOutputArchive.Tokenize(" ");
570          TIter next(arr);
571          while ((os=(TObjString*)next()))
572             fGridJDL->AddToOutputArchive(os->GetString().Data());
573          delete arr;
574       }      
575       fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
576       arr = fOutputFiles.Tokenize(" ");
577       TIter next(arr);
578       while ((os=(TObjString*)next())) fGridJDL->AddToOutputSandbox(os->GetString());
579       delete arr;
580 //      fGridJDL->SetPrice((UInt_t)fPrice);
581       fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
582       fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
583       if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
584       // Generate the JDL as a string
585       TString sjdl = fGridJDL->Generate();
586       Int_t index;
587       index = sjdl.Index("Executable");
588       if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
589       index = sjdl.Index("Split ");
590       if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
591       index = sjdl.Index("SplitMaxInputFileNumber");
592       if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
593       index = sjdl.Index("InputDataCollection");
594       if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
595       index = sjdl.Index("InputFile");
596       if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
597       index = sjdl.Index("InputDataList ");
598       if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
599       index = sjdl.Index("InputDataListFormat");
600       if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
601       index = sjdl.Index("Price");
602       if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
603       index = sjdl.Index("Requirements");
604       if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
605       index = sjdl.Index("Packages");
606       if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
607       index = sjdl.Index("User");
608       if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
609       index = sjdl.Index("TTL");
610       if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
611       index = sjdl.Index("OutputFile");
612       if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
613       index = sjdl.Index("OutputDir");
614       if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
615       index = sjdl.Index("OutputArchive");
616       if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
617       index = sjdl.Index("MaxInitFailed");
618       if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
619       index = sjdl.Index("MasterResubmitThreshold");
620       if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
621       sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
622       index = sjdl.Index("Validationcommand");
623       if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
624       sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
625       sjdl.ReplaceAll("(member", "\n   (member");
626       sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
627       sjdl.ReplaceAll("{", "{\n   ");
628       sjdl.ReplaceAll("};", "\n};");
629       sjdl.ReplaceAll("{\n   \n", "{\n");
630       sjdl.ReplaceAll("\n\n", "\n");
631       sjdl.ReplaceAll("OutputDirectory", "OutputDir");
632       sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
633       sjdl.Prepend("JobTag = \"Automatically generated analysis JDL\";\n");
634       index = sjdl.Index("JDLVariables");
635       if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
636       // Write jdl to file
637       ofstream out;
638       out.open(fJDLName.Data(), ios::out);
639       if (out.bad()) {
640          Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
641          return kFALSE;
642       }
643       out << sjdl << endl;
644    }
645    // Copy jdl to grid workspace   
646    if (!copy) {
647       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
648    } else {
649       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn working space", fJDLName.Data());
650       if (FileExists(fJDLName)) gGrid->Rm(fJDLName);
651       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s/%s", workdir.Data(), fJDLName.Data()));
652       if (fAdditionalLibs.Length()) {
653          arr = fAdditionalLibs.Tokenize(" ");
654          TObjString *os;
655          TIter next(arr);
656          while ((os=(TObjString*)next())) {
657             if (os->GetString().Contains(".so")) continue;
658             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
659             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
660             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
661          }   
662          delete arr;   
663       }
664       if (fPackages) {
665          TIter next(fPackages);
666          TObject *obj;
667          while ((obj=next())) {
668             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
669             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
670          }   
671       }      
672    } 
673    return kTRUE;
674 }
675
676 //______________________________________________________________________________
677 Bool_t AliAnalysisAlien::FileExists(const char *lfn) const
678 {
679 // Returns true if file exists.
680    if (!gGrid) {
681       Error("FileExists", "No connection to grid");
682       return kFALSE;
683    }
684    TGridResult *res = gGrid->Ls(lfn);
685    if (!res) return kFALSE;
686    TMap *map = dynamic_cast<TMap*>(res->At(0));
687    if (!map) {
688       delete res;
689       return kFALSE;
690    }   
691    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
692    if (!objs || !objs->GetString().Length()) {
693       delete res;
694       return kFALSE;
695    }
696    delete res;   
697    return kTRUE;
698 }
699
700 //______________________________________________________________________________
701 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
702 {
703 // Check input data type.
704    is_collection = kFALSE;
705    is_xml = kFALSE;
706    use_tags = kFALSE;
707    if (!gGrid) {
708       Error("CheckDataType", "No connection to grid");
709       return;
710    }
711    is_collection = IsCollection(lfn);
712    TString msg = "\n#####   file: ";
713    msg += lfn;
714    if (is_collection) {
715       msg += " type: raw_collection;";
716    // special treatment for collections
717       is_xml = kFALSE;
718       // check for tag files in the collection
719       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
720       if (!res) {
721          msg += " using_tags: No (unknown)";
722          Info("CheckDataType", msg.Data());
723          return;
724       }   
725       const char* typeStr = res->GetKey(0, "origLFN");
726       if (!typeStr || !strlen(typeStr)) {
727          msg += " using_tags: No (unknown)";
728          Info("CheckDataType", msg.Data());
729          return;
730       }   
731       TString file = typeStr;
732       use_tags = file.Contains(".tag");
733       if (use_tags) msg += " using_tags: Yes";
734       else          msg += " using_tags: No";
735       Info("CheckDataType", msg.Data());
736       return;
737    }
738    TString slfn(lfn);
739    slfn.ToLower();
740    is_xml = slfn.Contains(".xml");
741    if (is_xml) {
742    // Open xml collection and check if there are tag files inside
743       msg += " type: xml_collection;";
744       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
745       if (!coll) {
746          msg += " using_tags: No (unknown)";
747          Info("CheckDataType", msg.Data());
748          return;
749       }   
750       TMap *map = coll->Next();
751       if (!map) {
752          msg += " using_tags: No (unknown)";
753          Info("CheckDataType", msg.Data());
754          return;
755       }   
756       map = (TMap*)map->GetValue("");
757       TString file;
758       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
759       use_tags = file.Contains(".tag");
760       delete coll;
761       if (use_tags) msg += " using_tags: Yes";
762       else          msg += " using_tags: No";
763       Info("CheckDataType", msg.Data());
764       return;
765    }
766    use_tags = slfn.Contains(".tag");
767    if (slfn.Contains(".root")) msg += " type: root file;";
768    else                        msg += " type: unhnown file;";
769    if (use_tags) msg += " using_tags: Yes";
770    else          msg += " using_tags: No";
771    Info("CheckDataType", msg.Data());
772 }
773
774 //______________________________________________________________________________
775 void AliAnalysisAlien::EnablePackage(const char *package)
776 {
777 // Enables a par file supposed to exist in the current directory.
778    TString pkg(package);
779    pkg.ReplaceAll(".par", "");
780    pkg += ".par";
781    if (gSystem->AccessPathName(pkg)) {
782       Error("EnablePackage", "Package %s not found", pkg.Data());
783       return;
784    }
785    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
786       Info("EnablePackage", "AliEn plugin will use .par packages");
787    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
788    if (!fPackages) {
789       fPackages = new TObjArray();
790       fPackages->SetOwner();
791    }
792    fPackages->Add(new TObjString(pkg));
793 }      
794
795 //______________________________________________________________________________
796 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
797 {
798 // Returns true if file is a collection. Functionality duplicated from
799 // TAlien::Type() because we don't want to directly depend on TAlien.
800    if (!gGrid) {
801       Error("IsCollection", "No connection to grid");
802       return kFALSE;
803    }
804    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
805    if (!res) return kFALSE;
806    const char* typeStr = res->GetKey(0, "type");
807    if (!typeStr || !strlen(typeStr)) return kFALSE;
808    if (!strcmp(typeStr, "collection")) return kTRUE;
809    delete res;
810    return kFALSE;
811 }   
812
813 //______________________________________________________________________________
814 void AliAnalysisAlien::SetDefaults()
815 {
816 // Set default values for everything. What cannot be filled will be left empty.
817    if (fGridJDL) delete fGridJDL;
818    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
819    fPrice                      = 1;
820    fTTL                        = 30000;
821    fSplitMaxInputFileNumber    = 100;
822    fMaxInitFailed              = 0;
823    fMasterResubmitThreshold    = 0;
824    fNtestFiles                 = 10;
825    fRunNumbers                 = "";
826    fExecutable                 = "analysis.sh";
827    fArguments                  = "";
828    fAnalysisMacro              = "myAnalysis.C";
829    fAnalysisSource             = "";
830    fAdditionalLibs             = "";
831    fSplitMode                  = "se";
832    fAPIVersion                 = "";
833    fROOTVersion                = "";
834    fAliROOTVersion             = "";
835    fUser                       = "";  // Your alien user name
836    fGridWorkingDir             = "";
837    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
838    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
839    fGridOutputDir              = "output";
840    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
841    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
842    fInputFormat                = "xml-single";
843    fJDLName                    = "analysis.jdl";
844    fMergeExcludes              = "";
845 }   
846
847 //______________________________________________________________________________
848 Bool_t AliAnalysisAlien::MergeOutputs()
849 {
850 // Merge analysis outputs existing in the AliEn space.
851    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
852    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
853    if (!Connect()) {
854       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
855       return kFALSE;
856    }   
857    // Get the output path
858    TString output = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
859    if (!gGrid->Cd(output)) output = Form("/%s/%s", gGrid->GetHomeDirectory(), fGridOutputDir.Data());
860    if (!gGrid->Cd(output)) {
861       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
862       return kFALSE;
863    }
864    if (!fOutputFiles.Length()) {
865       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
866       return kFALSE;
867    }   
868    TObjArray *list = fOutputFiles.Tokenize(" ");
869    TIter next(list);
870    TObjString *str;
871    TString command;
872    TString output_file;
873    Bool_t merged = kTRUE;
874    while((str=(TObjString*)next())) {
875       output_file = str->GetString();
876       Int_t index = output_file.Index("@");
877       if (index > 0) output_file.Remove(index);
878       if (fMergeExcludes.Length() &&
879           fMergeExcludes.Contains(output_file.Data())) continue;
880       command = Form("find %s/ *%s", output.Data(), output_file.Data());
881       printf("command: %s\n", command.Data());
882       TGridResult *res = gGrid->Command(command);
883       if (!res) continue;
884       TFileMerger *fm = 0;
885       TIter nextmap(res);
886       TMap *map;
887       while ((map=(TMap*)nextmap())) {
888          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
889          if (!objs || !objs->GetString().Length()) {
890             delete res;
891             continue;
892          }   
893          if (!fm) {
894             fm = new TFileMerger(kFALSE);
895             fm->SetFastMethod(kTRUE);
896             fm->OutputFile(output_file);
897          }
898          fm->AddFile(objs->GetString());   
899       }
900       if (!fm || !fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
901          Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
902          merged = kFALSE;
903          delete res;
904          continue;
905       }
906       if (!fm->Merge()) {
907          Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
908          merged = kFALSE;
909       } else {
910          Info("MergeOutputs", "\n#####   Merged %d output files <%s>", fm->GetMergeList()->GetSize(), output_file.Data());
911       }   
912       delete fm;
913       delete res;
914    } 
915    if (!merged) {
916       Error("MergeOutputs", "Terminate() will  NOT be executed");
917    }  
918    return merged;
919 }   
920
921 //______________________________________________________________________________
922 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
923 {
924 // Use the output files connected to output containers from the analysis manager
925 // rather than the files defined by SetOutputFiles
926    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
927       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
928       analysis manager");
929    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
930 }
931       
932 //______________________________________________________________________________
933 void AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
934 {
935 // Start remote grid analysis.
936    
937    if (TestBit(AliAnalysisGrid::kOffline)) {
938       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
939       \n                         there nor any job run. You can revise the JDL and analysis \
940       \n                         macro then run the same in \"submit\" mode.");
941    } else if (TestBit(AliAnalysisGrid::kTest)) {
942       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
943       \n                         dataset.");
944    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
945       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
946       \n                         space and job submitted.");
947    } else if (TestBit(AliAnalysisGrid::kMerge)) {
948       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
949       return;
950    } else {
951       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
952    }   
953       
954    if (!Connect()) {
955       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
956       return;
957    }   
958    if (!CheckInputData()) {
959       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
960       return;
961    }   
962    CreateDataset(fDataPattern);
963    // Check if output files have to be taken from the analysis manager
964    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
965       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
966       if (!mgr || !mgr->IsInitialized()) {
967          Error("StartAnalysis", "You need an initialized analysis manager for this");
968          return;
969       }
970       fOutputFiles = "";
971       TIter next(mgr->GetOutputs());
972       AliAnalysisDataContainer *output;
973       while ((output=(AliAnalysisDataContainer*)next())) {
974          const char *filename = output->GetFileName();
975          if (!(strcmp(filename, "default"))) {
976             if (!mgr->GetOutputEventHandler()) continue;
977             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
978          }
979          if (fOutputFiles.Length()) fOutputFiles += " ";
980          fOutputFiles += filename;
981       }
982    }
983    WriteAnalysisFile();   
984    WriteAnalysisMacro();
985    WriteExecutable();
986    WriteValidationScript();
987    if (!CreateJDL()) return;
988    if (TestBit(AliAnalysisGrid::kOffline)) return;
989    if (TestBit(AliAnalysisGrid::kTest)) {
990       // Locally testing the analysis
991       Info("StartAnalysis", "\n_______________________________________________________________________ \
992       \n   Running analysis script in a daughter shell as on a worker node \
993       \n_______________________________________________________________________");
994       TObjArray *list = fOutputFiles.Tokenize(" ");
995       TIter next(list);
996       TObjString *str;
997       TString output_file;
998       while((str=(TObjString*)next())) {
999          output_file = str->GetString();
1000          Int_t index = output_file.Index("@");
1001          if (index > 0) output_file.Remove(index);         
1002          gSystem->Exec(Form("rm %s", output_file.Data()));
1003       }
1004       delete list;
1005       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1006       gSystem->Exec("bash validate.sh");
1007 //      gSystem->Exec("cat stdout");
1008       return;
1009    }
1010    // Submit AliEn job
1011    CdWork();
1012    TGridResult *res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1013    TString jobID = "";
1014    if (res) {
1015       const char *cjobId = res->GetKey(0,"jobId");
1016       if (!cjobId) {
1017          Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1018          return;
1019       } else {
1020          Info("StartAnalysis", "\n_______________________________________________________________________ \
1021          \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1022       \n_______________________________________________________________________",
1023                 fJDLName.Data(), cjobId);
1024          jobID = cjobId;      
1025       }          
1026       delete res;
1027    }   
1028    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1029    \n You may exit at any time and terminate the job later using the option <terminate> \
1030    \n ##################################################################################", jobID.Data());
1031    //gGrid->Shell();
1032    gSystem->Exec("aliensh");
1033 }
1034
1035 //______________________________________________________________________________
1036 void AliAnalysisAlien::WriteAnalysisFile()
1037 {
1038 // Write current analysis manager into the file analysis.root
1039    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1040       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1041       if (!mgr || !mgr->IsInitialized()) {
1042          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1043          return;
1044       }
1045       // Check analysis type
1046       TObject *handler;
1047       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1048       handler = (TObject*)mgr->GetInputEventHandler();
1049       if (handler) {
1050          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1051          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1052       }
1053       TDirectory *cdir = gDirectory;
1054       TFile *file = TFile::Open("analysis.root", "RECREATE");
1055       if (file) {
1056          mgr->Write();
1057          delete file;
1058       }
1059       if (cdir) cdir->cd();
1060       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1061    }   
1062    Bool_t copy = kTRUE;
1063    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1064    if (copy) {
1065       CdWork();
1066       TString workdir = gGrid->GetHomeDirectory();
1067       workdir += fGridWorkingDir;
1068       Info("CreateJDL", "\n#####   Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1069       if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1070       TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1071    }   
1072 }
1073
1074 //______________________________________________________________________________
1075 void AliAnalysisAlien::WriteAnalysisMacro()
1076 {
1077 // Write the analysis macro that will steer the analysis in grid mode.
1078    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1079       ofstream out;
1080       out.open(fAnalysisMacro.Data(), ios::out);
1081       if (!out.good()) {
1082          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1083          return;
1084       }
1085       TString func = fAnalysisMacro;
1086       TString type = "ESD";
1087       TString comment = "// Analysis using ";
1088       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1089       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1090          type = "AOD";
1091          comment += "AOD";
1092       }   
1093       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1094       else comment += " data";
1095       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1096       func.ReplaceAll(".C", "");
1097       out << "void " << func.Data() << "()" << endl; 
1098       out << "{" << endl;
1099       out << comment.Data() << endl;
1100       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1101       out << "// load base root libraries" << endl;
1102       out << "   gSystem->Load(\"libTree\");" << endl;
1103       out << "   gSystem->Load(\"libGeom\");" << endl;
1104       out << "   gSystem->Load(\"libVMC\");" << endl;
1105       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1106       if (!fPackages) {
1107          out << "// Load analysis framework libraries" << endl;
1108          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1109          out << "   gSystem->Load(\"libESD\");" << endl;
1110          out << "   gSystem->Load(\"libAOD\");" << endl;
1111          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1112          out << "   gSystem->Load(\"libANALYSISalice\");" << endl << endl;
1113          out << "// include path (remove if using par files)" << endl;
1114          out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
1115          if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl << endl;
1116       } else {
1117          out << "// Compile all par packages" << endl;
1118          TIter next(fPackages);
1119          TObject *obj;
1120          while ((obj=next())) 
1121             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1122       }   
1123       if (fAdditionalLibs.Length()) {
1124          out << "// Add aditional AliRoot libraries" << endl;
1125          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1126          TIter next(list);
1127          TObjString *str;
1128          while((str=(TObjString*)next())) {
1129             if (str->GetString().Contains(".so"))
1130                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1131          }
1132          if (list) delete list;
1133       }
1134       out << endl;
1135       out << "// analysis source to be compiled at runtime (if any)" << endl;
1136       if (fAnalysisSource.Length()) {
1137          TObjArray *list = fAnalysisSource.Tokenize(" ");
1138          TIter next(list);
1139          TObjString *str;
1140          while((str=(TObjString*)next())) {
1141             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1142          }   
1143          if (list) delete list;
1144       }
1145       out << endl;
1146       out << "// connect to AliEn and make the chain" << endl;
1147       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1148       if (IsUsingTags()) {
1149          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1150       } else {
1151          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;      
1152       }   
1153       out << "// read the analysis manager from file" << endl;
1154       out << "   TFile *file = TFile::Open(\"analysis.root\");" << endl;
1155       out << "   if (!file) return;" << endl; 
1156       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1157       out << "   AliAnalysisManager *mgr = 0;" << endl;
1158       out << "   TKey *key;" << endl;
1159       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1160       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1161       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1162       out << "   };" << endl;
1163       out << "   if (!mgr) {" << endl;
1164       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1165       out << "      return;" << endl;
1166       out << "   }" << endl << endl;
1167       out << "   mgr->PrintStatus();" << endl;
1168       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1169       out << "}" << endl << endl;
1170       if (IsUsingTags()) {
1171          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1172          out << "{" << endl;
1173          out << "// Create a chain using tags from the xml file." << endl;
1174          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1175          out << "   if (!coll) {" << endl;
1176          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1177          out << "      return NULL;" << endl;
1178          out << "   }" << endl;
1179          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1180          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1181          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1182          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1183          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1184          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1185          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1186          out << "   // Check if the cuts configuration file was provided" << endl;
1187          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1188          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1189          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1190          out << "   }" << endl;
1191          out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1192          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1193          out << "   chain->ls();" << endl;
1194          out << "   return chain;" << endl;
1195          out << "}" << endl;
1196          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1197             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1198             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1199             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1200             msg += "                      AliDetectorTagCuts *detCuts,\n";
1201             msg += "                      AliEventTagCuts *evCuts)";
1202             Info("WriteAnalysisMacro", msg.Data());
1203          }
1204       } else {
1205          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1206          out << "{" << endl;
1207          out << "// Create a chain using url's from xml file" << endl;
1208          out << "   TString treename = type;" << endl;
1209          out << "   treename.ToLower();" << endl;
1210          out << "   treename += \"Tree\";" << endl;
1211          out << "   printf(\"***************************************\\n\");" << endl;
1212          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1213          out << "   printf(\"***************************************\\n\");" << endl;
1214          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1215          out << "   if (!coll) {" << endl;
1216          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1217          out << "      return NULL;" << endl;
1218          out << "   }" << endl;
1219          out << "   TChain *chain = new TChain(treename);" << endl;
1220          out << "   coll->Reset();" << endl;
1221          out << "   while (coll->Next()) chain->Add(coll->GetTURL(\"\"));" << endl;
1222          out << "   if (!chain->GetNtrees()) {" << endl;
1223          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1224          out << "      return NULL;" << endl;
1225          out << "   }" << endl;
1226          out << "   return chain;" << endl;
1227          out << "}" << endl;
1228       }   
1229       if (fPackages) {
1230          out << "Bool_t SetupPar(const char *package) {" << endl;
1231          out << "// Compile the package and set it up." << endl;
1232          out << "   TString pkgdir = package;" << endl;
1233          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1234          out << "   gSystem->Exec(Form(\"tar xvzf %s\", package));" << endl;
1235          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1236          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1237          out << "   // Check for BUILD.sh and execute" << endl;
1238          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1239          out << "      printf(\"*******************************\\n\");" << endl;
1240          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1241          out << "      printf(\"*******************************\\n\");" << endl;
1242          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1243          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", package);" << endl;
1244          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1245          out << "         return kFALSE;" << endl;
1246          out << "      }" << endl;
1247          out << "   } else {" << endl;
1248          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", package);" << endl;
1249          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1250          out << "      return kFALSE;" << endl;
1251          out << "   }" << endl;
1252          out << "   // Check for SETUP.C and execute" << endl;
1253          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1254          out << "      printf(\"*******************************\\n\");" << endl;
1255          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1256          out << "      printf(\"*******************************\\n\");" << endl;
1257          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1258          out << "   } else {" << endl;
1259          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", package);" << endl;
1260          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1261          out << "      return kFALSE;" << endl;
1262          out << "   }" << endl;
1263          out << "   // Restore original workdir" << endl;
1264          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1265          out << "   return kTRUE;" << endl;
1266          out << "}" << endl;
1267       }
1268       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1269    }   
1270    Bool_t copy = kTRUE;
1271    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1272    if (copy) {
1273       CdWork();
1274       TString workdir = gGrid->GetHomeDirectory();
1275       workdir += fGridWorkingDir;
1276       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1277       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1278          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1279          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1280          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1281       }   
1282       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1283       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1284    }
1285 }
1286
1287 //______________________________________________________________________________
1288 void AliAnalysisAlien::WriteExecutable()
1289 {
1290 // Generate the alien executable script.
1291    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1292       ofstream out;
1293       out.open(fExecutable.Data(), ios::out);
1294       if (out.bad()) {
1295          Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1296          return;
1297       }
1298       out << "#!/bin/bash" << endl;
1299       out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1300       out << "echo \"=========================================\"" << endl; 
1301       out << "echo \"############## PATH : ##############\"" << endl;
1302       out << "echo $PATH" << endl;
1303       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1304       out << "echo $LD_LIBRARY_PATH" << endl;
1305       out << "echo \"############## ROOTSYS : ##############\"" << endl;
1306       out << "echo $ROOTSYS" << endl;
1307       out << "echo \"############## which root : ##############\"" << endl;
1308       out << "which root" << endl;
1309       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1310       out << "echo $ALICE_ROOT" << endl;
1311       out << "echo \"############## which aliroot : ##############\"" << endl;
1312       out << "which aliroot" << endl;
1313       out << "echo \"=========================================\"" << endl << endl;
1314 //      if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1315       out << "root -b -q "; 
1316       out << fAnalysisMacro.Data() << endl << endl;
1317       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1318    }   
1319    Bool_t copy = kTRUE;
1320    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1321    if (copy) {
1322       CdWork();
1323       TString workdir = gGrid->GetHomeDirectory();
1324       workdir += fGridWorkingDir;
1325       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1326       if (FileExists(executable)) gGrid->Rm(executable);
1327       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1328       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1329    } 
1330 }
1331
1332 //______________________________________________________________________________
1333 void AliAnalysisAlien::WriteValidationScript()
1334 {
1335 // Generate the alien validation script.
1336    // Generate the validation script
1337    TObjString *os;
1338    if (!Connect()) {
1339       Error("WriteValidationScript", "Alien connection required");
1340       return;
1341    }
1342    TString out_stream = "";
1343    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1344    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1345       ofstream out;
1346       out.open("validate.sh", ios::out);
1347       out << "#!/bin/bash" << endl;
1348       out << "##################################################" << endl;
1349       out << "validateout=`dirname $0`" << endl;
1350       out << "validatetime=`date`" << endl;
1351       out << "validated=\"0\";" << endl;
1352       out << "error=0" << endl;
1353       out << "if [ -z $validateout ]" << endl;
1354       out << "then" << endl;
1355       out << "    validateout=\".\"" << endl;
1356       out << "fi" << endl << endl;
1357       out << "cd $validateout;" << endl;
1358       out << "validateworkdir=`pwd`;" << endl << endl;
1359       out << "echo \"*******************************************************\"" << out_stream << endl;
1360       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
1361       out << "" << endl;
1362       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
1363       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
1364       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
1365       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1366       out << "ls -la ./"  << out_stream << endl;
1367       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
1368       out << "##################################################" << endl;
1369       TObjArray *arr = fOutputFiles.Tokenize(" ");
1370       TIter next1(arr);
1371       TString output_file;
1372       while ((os=(TObjString*)next1())) { 
1373          output_file = os->GetString();
1374          Int_t index = output_file.Index("@");
1375          if (index > 0) output_file.Remove(index);
1376          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1377          out << "   error=1" << endl;
1378          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
1379          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1380          out << "fi" << endl;
1381       }   
1382       delete arr;
1383       out << "if [ $error = 0 ] ; then" << endl;
1384       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
1385       out << "fi" << endl;
1386
1387       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1388       out << "echo \"*******************************************************\""  << out_stream << endl;
1389       out << "cd -" << endl;
1390       out << "exit $error" << endl;
1391    }    
1392    Bool_t copy = kTRUE;
1393    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1394    if (copy) {
1395       CdWork();
1396       TString workdir = gGrid->GetHomeDirectory();
1397       workdir += fGridWorkingDir;
1398       Info("CreateJDL", "\n#####   Copying validation script <validate.sh> to your AliEn working space");
1399       if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1400       TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
1401    } 
1402 }