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