]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Small typo fixed
[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          if (!os->GetString().Contains("@") && fCloseSE.Length())
796             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
797          else
798             fGridJDL->AddToOutputSandbox(os->GetString());
799       }   
800       delete arr;
801 //      fGridJDL->SetPrice((UInt_t)fPrice);
802       fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
803       fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
804       if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
805       // Write a jdl with 2 input parameters: collection name and output dir name.
806       WriteJDL(copy);
807    }
808    // Copy jdl to grid workspace   
809    if (copy) {
810       if (fAdditionalLibs.Length()) {
811          arr = fAdditionalLibs.Tokenize(" ");
812          TObjString *os;
813          TIter next(arr);
814          while ((os=(TObjString*)next())) {
815             if (os->GetString().Contains(".so")) continue;
816             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
817             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
818             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
819          }   
820          delete arr;   
821       }
822       if (fPackages) {
823          TIter next(fPackages);
824          TObject *obj;
825          while ((obj=next())) {
826             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
827             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
828          }   
829       }      
830    } 
831    return kTRUE;
832 }
833
834 //______________________________________________________________________________
835 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
836 {
837 // Writes one or more JDL's corresponding to findex. If findex is negative,
838 // all run numbers are considered in one go (jdl). For non-negative indices
839 // they correspond to the indices in the array fInputFiles.
840    if (!fInputFiles) return kFALSE;
841    TObjString *os;
842    TString workdir = gGrid->GetHomeDirectory();
843    workdir += fGridWorkingDir;
844    
845    if (!fRunNumbers.Length() && !fRunRange[0]) {
846       // One jdl with no parameters in case input data is specified by name.
847       TIter next(fInputFiles);
848       while ((os=(TObjString*)next()))
849          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
850       fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
851    } else {
852       // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
853       fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
854       fGridJDL->SetOutputDirectory(Form("%s/$2#alien_counter_03i#", fGridOutputDir.Data()));
855    }
856       
857
858    // Generate the JDL as a string
859    TString sjdl = fGridJDL->Generate();
860    Int_t index;
861    index = sjdl.Index("Executable");
862    if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
863    index = sjdl.Index("Split ");
864    if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
865    index = sjdl.Index("SplitMaxInputFileNumber");
866    if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
867    index = sjdl.Index("InputDataCollection");
868    if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
869    index = sjdl.Index("InputFile");
870    if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
871    index = sjdl.Index("InputDataList ");
872    if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
873    index = sjdl.Index("InputDataListFormat");
874    if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
875    index = sjdl.Index("Price");
876    if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
877    index = sjdl.Index("Requirements");
878    if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
879    index = sjdl.Index("Packages");
880    if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
881    index = sjdl.Index("User =");
882    if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
883    index = sjdl.Index("TTL");
884    if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
885    index = sjdl.Index("OutputFile");
886    if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
887    index = sjdl.Index("OutputDir");
888    if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
889    index = sjdl.Index("OutputArchive");
890    if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
891    index = sjdl.Index("MaxInitFailed");
892    if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
893    index = sjdl.Index("MasterResubmitThreshold");
894    if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
895    sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
896    index = sjdl.Index("Validationcommand");
897    if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
898    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
899    sjdl.ReplaceAll("(member", "\n   (member");
900    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
901    sjdl.ReplaceAll("{", "{\n   ");
902    sjdl.ReplaceAll("};", "\n};");
903    sjdl.ReplaceAll("{\n   \n", "{\n");
904    sjdl.ReplaceAll("\n\n", "\n");
905    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
906    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
907    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
908    index = sjdl.Index("JDLVariables");
909    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
910    // Write jdl to file
911    ofstream out;
912    out.open(fJDLName.Data(), ios::out);
913    if (out.bad()) {
914       Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
915       return kFALSE;
916    }
917    out << sjdl << endl;
918
919    // Copy jdl to grid workspace   
920    if (!copy) {
921       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
922    } else {
923       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
924       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
925       if (fProductionMode)
926          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
927       if (FileExists(locjdl)) gGrid->Rm(locjdl);
928       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
929    } 
930    return kTRUE;
931 }
932
933 //______________________________________________________________________________
934 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
935 {
936 // Returns true if file exists.
937    if (!gGrid) return kFALSE;
938    TGridResult *res = gGrid->Ls(lfn);
939    if (!res) return kFALSE;
940    TMap *map = dynamic_cast<TMap*>(res->At(0));
941    if (!map) {
942       delete res;
943       return kFALSE;
944    }   
945    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
946    if (!objs || !objs->GetString().Length()) {
947       delete res;
948       return kFALSE;
949    }
950    delete res;   
951    return kTRUE;
952 }
953
954 //______________________________________________________________________________
955 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
956 {
957 // Check input data type.
958    is_collection = kFALSE;
959    is_xml = kFALSE;
960    use_tags = kFALSE;
961    if (!gGrid) {
962       Error("CheckDataType", "No connection to grid");
963       return;
964    }
965    is_collection = IsCollection(lfn);
966    TString msg = "\n#####   file: ";
967    msg += lfn;
968    if (is_collection) {
969       msg += " type: raw_collection;";
970    // special treatment for collections
971       is_xml = kFALSE;
972       // check for tag files in the collection
973       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
974       if (!res) {
975          msg += " using_tags: No (unknown)";
976          Info("CheckDataType", msg.Data());
977          return;
978       }   
979       const char* typeStr = res->GetKey(0, "origLFN");
980       if (!typeStr || !strlen(typeStr)) {
981          msg += " using_tags: No (unknown)";
982          Info("CheckDataType", msg.Data());
983          return;
984       }   
985       TString file = typeStr;
986       use_tags = file.Contains(".tag");
987       if (use_tags) msg += " using_tags: Yes";
988       else          msg += " using_tags: No";
989       Info("CheckDataType", msg.Data());
990       return;
991    }
992    TString slfn(lfn);
993    slfn.ToLower();
994    is_xml = slfn.Contains(".xml");
995    if (is_xml) {
996    // Open xml collection and check if there are tag files inside
997       msg += " type: xml_collection;";
998       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
999       if (!coll) {
1000          msg += " using_tags: No (unknown)";
1001          Info("CheckDataType", msg.Data());
1002          return;
1003       }   
1004       TMap *map = coll->Next();
1005       if (!map) {
1006          msg += " using_tags: No (unknown)";
1007          Info("CheckDataType", msg.Data());
1008          return;
1009       }   
1010       map = (TMap*)map->GetValue("");
1011       TString file;
1012       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1013       use_tags = file.Contains(".tag");
1014       delete coll;
1015       if (use_tags) msg += " using_tags: Yes";
1016       else          msg += " using_tags: No";
1017       Info("CheckDataType", msg.Data());
1018       return;
1019    }
1020    use_tags = slfn.Contains(".tag");
1021    if (slfn.Contains(".root")) msg += " type: root file;";
1022    else                        msg += " type: unhnown file;";
1023    if (use_tags) msg += " using_tags: Yes";
1024    else          msg += " using_tags: No";
1025    Info("CheckDataType", msg.Data());
1026 }
1027
1028 //______________________________________________________________________________
1029 void AliAnalysisAlien::EnablePackage(const char *package)
1030 {
1031 // Enables a par file supposed to exist in the current directory.
1032    TString pkg(package);
1033    pkg.ReplaceAll(".par", "");
1034    pkg += ".par";
1035    if (gSystem->AccessPathName(pkg)) {
1036       Error("EnablePackage", "Package %s not found", pkg.Data());
1037       return;
1038    }
1039    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1040       Info("EnablePackage", "AliEn plugin will use .par packages");
1041    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1042    if (!fPackages) {
1043       fPackages = new TObjArray();
1044       fPackages->SetOwner();
1045    }
1046    fPackages->Add(new TObjString(pkg));
1047 }      
1048
1049 //______________________________________________________________________________
1050 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1051 {
1052 // Get job status for all jobs with jobid>jobidstart.
1053    static char mstatus[20];
1054    mstatus[0] = '\0';
1055    nrunning = 0;
1056    nwaiting = 0;
1057    nerror   = 0;
1058    ndone    = 0;
1059    TGridJobStatusList *list = gGrid->Ps("");
1060    if (!list) return mstatus;
1061    Int_t nentries = list->GetSize();
1062    TGridJobStatus *status;
1063    Int_t pid;
1064    for (Int_t ijob=0; ijob<nentries; ijob++) {
1065       status = (TGridJobStatus *)list->At(ijob);
1066       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1067       if (pid<jobidstart) continue;
1068       if (pid == lastid) {
1069          gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1070       }   
1071       switch (status->GetStatus()) {
1072          case TGridJobStatus::kWAITING:
1073             nwaiting++; break;
1074          case TGridJobStatus::kRUNNING:
1075             nrunning++; break;
1076          case TGridJobStatus::kABORTED:
1077          case TGridJobStatus::kFAIL:
1078          case TGridJobStatus::kUNKNOWN:
1079             nerror++; break;
1080          case TGridJobStatus::kDONE:
1081             ndone++;
1082       }
1083    }
1084    list->Delete();
1085    delete list;
1086    return mstatus;
1087 }
1088
1089 //______________________________________________________________________________
1090 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1091 {
1092 // Returns true if file is a collection. Functionality duplicated from
1093 // TAlien::Type() because we don't want to directly depend on TAlien.
1094    if (!gGrid) {
1095       Error("IsCollection", "No connection to grid");
1096       return kFALSE;
1097    }
1098    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1099    if (!res) return kFALSE;
1100    const char* typeStr = res->GetKey(0, "type");
1101    if (!typeStr || !strlen(typeStr)) return kFALSE;
1102    if (!strcmp(typeStr, "collection")) return kTRUE;
1103    delete res;
1104    return kFALSE;
1105 }   
1106
1107 //______________________________________________________________________________
1108 void AliAnalysisAlien::Print(Option_t *) const
1109 {
1110 // Print current plugin settings.
1111    printf("### AliEn analysis plugin current settings ###\n");
1112    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1113    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1114    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1115    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1116    if (fUser.Length()) 
1117    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1118    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1119    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1120    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1121    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1122    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1123    if (fRunNumbers.Length()) 
1124    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1125    if (fRunRange[0])
1126    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
1127    if (!fRunRange[0] && !fRunNumbers.Length()) {
1128       TIter next(fInputFiles);
1129       TObject *obj;
1130       TString list;
1131       while ((obj=next())) list += obj->GetName();
1132       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1133    }
1134    if (TestBit(AliAnalysisGrid::kTest))
1135    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1136    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1137    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1138    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1139    printf("=====================================================================\n");
1140    printf("=   Job price: ___________________________________ %d\n", fPrice);
1141    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
1142    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1143    if (fMaxInitFailed>0) 
1144    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1145    if (fMasterResubmitThreshold>0) 
1146    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1147    if (fNrunsPerMaster>0)
1148    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1149    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1150    printf("=   Name of the generated execution script: ______ %s\n",fExecutable.Data());
1151    if (fArguments.Length()) 
1152    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
1153    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1154    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1155    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1156    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1157    if (fDatasetName)
1158    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1159    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1160    if (fIncludePath.Data())
1161    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1162    if (fCloseSE.Length())
1163    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1164    if (fFriendChainName.Length())
1165    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1166    if (fPackages) {
1167       TIter next(fPackages);
1168       TObject *obj;
1169       TString list;
1170       while ((obj=next())) list += obj->GetName();
1171       printf("=   Par files to be used: ________________________ %s\n", list.Data());
1172    }   
1173 }
1174
1175 //______________________________________________________________________________
1176 void AliAnalysisAlien::SetDefaults()
1177 {
1178 // Set default values for everything. What cannot be filled will be left empty.
1179    if (fGridJDL) delete fGridJDL;
1180    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1181    fPrice                      = 1;
1182    fTTL                        = 30000;
1183    fSplitMaxInputFileNumber    = 100;
1184    fMaxInitFailed              = 0;
1185    fMasterResubmitThreshold    = 0;
1186    fNtestFiles                 = 10;
1187    fRunRange[0]                = 0;
1188    fRunRange[1]                = 0;
1189    fNrunsPerMaster             = 1;
1190    fMaxMergeFiles              = 100;
1191    fRunNumbers                 = "";
1192    fExecutable                 = "analysis.sh";
1193    fArguments                  = "";
1194    fAnalysisMacro              = "myAnalysis.C";
1195    fAnalysisSource             = "";
1196    fAdditionalLibs             = "";
1197    fSplitMode                  = "se";
1198    fAPIVersion                 = "";
1199    fROOTVersion                = "";
1200    fAliROOTVersion             = "";
1201    fUser                       = "";  // Your alien user name
1202    fGridWorkingDir             = "";
1203    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1204    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1205    fFriendChainName            = "";
1206    fGridOutputDir              = "output";
1207    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1208    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1209    fInputFormat                = "xml-single";
1210    fJDLName                    = "analysis.jdl";
1211    fJobTag                     = "Automatically generated analysis JDL";
1212    fMergeExcludes              = "";
1213 }   
1214
1215 //______________________________________________________________________________
1216 Bool_t AliAnalysisAlien::MergeOutputs()
1217 {
1218 // Merge analysis outputs existing in the AliEn space.
1219    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1220    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1221    if (!Connect()) {
1222       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1223       return kFALSE;
1224    }   
1225    // Get the output path
1226    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1227    if (!gGrid->Cd(fGridOutputDir)) {
1228       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1229       return kFALSE;
1230    }
1231    if (!fOutputFiles.Length()) {
1232       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1233       return kFALSE;
1234    }   
1235    TObjArray *list = fOutputFiles.Tokenize(" ");
1236    TIter next(list);
1237    TObjString *str;
1238    TString command;
1239    TString output_file;
1240    TString output_chunk;
1241    TString previous_chunk;
1242    Int_t count_chunk = 0;
1243    Int_t count_zero = fMaxMergeFiles;
1244    Bool_t merged = kTRUE;
1245    while((str=(TObjString*)next())) {
1246       output_file = str->GetString();
1247       Int_t index = output_file.Index("@");
1248       if (index > 0) output_file.Remove(index);
1249       // Skip already merged outputs
1250       if (!gSystem->AccessPathName(output_file)) {
1251          Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1252          continue;
1253       }   
1254       if (fMergeExcludes.Length() &&
1255           fMergeExcludes.Contains(output_file.Data())) continue;
1256       // Perform a 'find' command in the output directory, looking for registered outputs    
1257       command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1258       printf("command: %s\n", command.Data());
1259       TGridResult *res = gGrid->Command(command);
1260       if (!res) continue;
1261       TFileMerger *fm = 0;
1262       TIter nextmap(res);
1263       TMap *map = 0;
1264       previous_chunk = "";
1265       count_chunk = 0;
1266       // Check if there is a merge operation to resume
1267       output_chunk = output_file;
1268       output_chunk.ReplaceAll(".root", "_*.root");
1269       if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1270          while (1) {
1271             for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1272             if (!map) {
1273                Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1274                delete res;
1275                return kFALSE;
1276             }
1277             output_chunk = output_file;
1278             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1279             printf("%s\n", output_chunk.Data());
1280             count_chunk++;
1281             if (gSystem->AccessPathName(output_chunk)) continue;
1282             // Merged file with chunks up to <count_chunk> found
1283             printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1284             previous_chunk = output_chunk;
1285             break;
1286          }
1287       }
1288       count_zero = fMaxMergeFiles;
1289       while ((map=(TMap*)nextmap())) {
1290       // Loop 'find' results and get next LFN
1291          if (count_zero == fMaxMergeFiles) {
1292             // First file in chunk - create file merger and add previous chunk if any.
1293             fm = new TFileMerger(kFALSE);
1294             fm->SetFastMethod(kTRUE);
1295             if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1296             output_chunk = output_file;
1297             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1298          }
1299          // If last file found, put merged results in the output file
1300          if (map == res->Last()) output_chunk = output_file;
1301          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1302          if (!objs || !objs->GetString().Length()) {
1303             // Nothing found - skip this output
1304             delete res;
1305             delete fm;
1306             break;
1307          } 
1308          // Add file to be merged and decrement chunk counter.
1309          fm->AddFile(objs->GetString());
1310          count_zero--;
1311          if (count_zero==0 || map == res->Last()) {            
1312             fm->OutputFile(output_chunk);
1313             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1314             // Nothing found - skip this output
1315                Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1316                delete res;
1317                delete fm;
1318                break;
1319             }
1320             // Merge the outputs, then go to next chunk      
1321             if (!fm->Merge()) {
1322                Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1323                delete res;
1324                delete fm;
1325                merged = kFALSE;
1326                break;
1327             } else {
1328                Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1329                gSystem->Unlink(previous_chunk);
1330             }
1331             if (map == res->Last()) {
1332                delete res;
1333                delete fm;
1334                break;
1335             }      
1336             count_chunk++;
1337             count_zero = fMaxMergeFiles;
1338             previous_chunk = output_chunk;
1339          }
1340       }
1341    } 
1342    if (!merged) {
1343       Error("MergeOutputs", "Terminate() will  NOT be executed");
1344    }  
1345    return merged;
1346 }   
1347
1348 //______________________________________________________________________________
1349 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1350 {
1351 // Use the output files connected to output containers from the analysis manager
1352 // rather than the files defined by SetOutputFiles
1353    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1354       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1355       analysis manager");
1356    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1357 }
1358       
1359 //______________________________________________________________________________
1360 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1361 {
1362 // Start remote grid analysis.
1363    
1364    // Check if output files have to be taken from the analysis manager
1365    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1366       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1367       if (!mgr || !mgr->IsInitialized()) {
1368          Error("StartAnalysis", "You need an initialized analysis manager for this");
1369          return kFALSE;
1370       }
1371       fOutputFiles = "";
1372       TIter next(mgr->GetOutputs());
1373       AliAnalysisDataContainer *output;
1374       while ((output=(AliAnalysisDataContainer*)next())) {
1375          const char *filename = output->GetFileName();
1376          if (!(strcmp(filename, "default"))) {
1377             if (!mgr->GetOutputEventHandler()) continue;
1378             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1379          }
1380          if (fOutputFiles.Length()) fOutputFiles += " ";
1381          fOutputFiles += filename;
1382       }
1383       // Add extra files registered to the analysis manager
1384       if (mgr->GetExtraFiles().Length()) {
1385          if (fOutputFiles.Length()) fOutputFiles += " ";
1386          fOutputFiles += mgr->GetExtraFiles();
1387       }   
1388    }
1389 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1390    if (TestBit(AliAnalysisGrid::kOffline)) {
1391       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1392       \n                         there nor any job run. You can revise the JDL and analysis \
1393       \n                         macro then run the same in \"submit\" mode.");
1394    } else if (TestBit(AliAnalysisGrid::kTest)) {
1395       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1396       \n                         dataset.");
1397    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1398       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1399       \n                         space and job submitted.");
1400    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1401       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1402       return kTRUE;
1403    } else {
1404       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1405    }   
1406       
1407    if (!Connect()) {
1408       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1409       return kFALSE;
1410    }
1411    Print();   
1412    if (!CheckInputData()) {
1413       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1414       return kFALSE;
1415    }   
1416    CreateDataset(fDataPattern);
1417    WriteAnalysisFile();   
1418    WriteAnalysisMacro();
1419    WriteExecutable();
1420    WriteValidationScript();
1421    if (!CreateJDL()) return kFALSE;
1422    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1423    if (TestBit(AliAnalysisGrid::kTest)) {
1424       // Locally testing the analysis
1425       Info("StartAnalysis", "\n_______________________________________________________________________ \
1426       \n   Running analysis script in a daughter shell as on a worker node \
1427       \n_______________________________________________________________________");
1428       TObjArray *list = fOutputFiles.Tokenize(" ");
1429       TIter next(list);
1430       TObjString *str;
1431       TString output_file;
1432       while((str=(TObjString*)next())) {
1433          output_file = str->GetString();
1434          Int_t index = output_file.Index("@");
1435          if (index > 0) output_file.Remove(index);         
1436          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1437       }
1438       delete list;
1439       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1440       gSystem->Exec("bash validate.sh");
1441 //      gSystem->Exec("cat stdout");
1442       return kFALSE;
1443    }
1444    // Check if submitting is managed by LPM manager
1445    if (fProductionMode) {
1446       TString prodfile = fJDLName;
1447       prodfile.ReplaceAll(".jdl", ".prod");
1448       WriteProductionFile(prodfile);
1449       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1450       return kFALSE;
1451    }   
1452    // Submit AliEn job(s)
1453    gGrid->Cd(fGridOutputDir);
1454    TGridResult *res;
1455    TString jobID = "";
1456    if (!fRunNumbers.Length() && !fRunRange[0]) {
1457       // Submit a given xml or a set of runs
1458       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1459       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1460       if (res) {
1461          const char *cjobId = res->GetKey(0,"jobId");
1462          if (!cjobId) {
1463             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1464             return kFALSE;
1465          } else {
1466             Info("StartAnalysis", "\n_______________________________________________________________________ \
1467             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1468             \n_______________________________________________________________________",
1469                    fJDLName.Data(), cjobId);
1470             jobID = cjobId;      
1471          }          
1472          delete res;
1473       }   
1474    } else {
1475       // Submit for a range of enumeration of runs.
1476       Submit();
1477    }   
1478          
1479    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1480    \n You may exit at any time and terminate the job later using the option <terminate> \
1481    \n ##################################################################################", jobID.Data());
1482    gSystem->Exec("aliensh");
1483    return kTRUE;
1484 }
1485
1486 //______________________________________________________________________________
1487 void AliAnalysisAlien::Submit()
1488 {
1489 // Submit all master jobs.
1490    Int_t nmasterjobs = fInputFiles->GetEntries();
1491    Long_t tshoot = gSystem->Now();
1492    if (!fNsubmitted) SubmitNext();
1493    while (fNsubmitted < nmasterjobs) {
1494       Long_t now = gSystem->Now();
1495       if ((now-tshoot)>30000) {
1496          tshoot = now;
1497          SubmitNext();
1498       }   
1499    }
1500 }
1501
1502 //______________________________________________________________________________
1503 void AliAnalysisAlien::SubmitNext()
1504 {
1505 // Submit next bunch of master jobs if the queue is free.
1506    static Bool_t iscalled = kFALSE;
1507    static Int_t firstmaster = 0;
1508    static Int_t lastmaster = 0;
1509    static Int_t npermaster  = 0;
1510    if (iscalled) return;
1511    iscalled = kTRUE;
1512    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1513    Int_t ntosubmit = 0;
1514    TGridResult *res;
1515    TString jobID = "";
1516    if (!fNsubmitted) ntosubmit = 1;
1517    else {
1518       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1519       printf("=== master %d: %s\n", lastmaster, status.Data());
1520       // If last master not split, just return
1521       if (status != "SPLIT") {iscalled = kFALSE; return;}
1522       // No more than 100 waiting jobs
1523       if (nwaiting>100) {iscalled = kFALSE; return;}
1524       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
1525       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1526       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
1527              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1528    }
1529    Int_t nmasterjobs = fInputFiles->GetEntries();
1530    for (Int_t i=0; i<ntosubmit; i++) {
1531       // Submit for a range of enumeration of runs.
1532       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1533       TString query;
1534       query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1535       printf("********* %s\n",query.Data());
1536       res = gGrid->Command(query);
1537       if (res) {
1538          TString cjobId1 = res->GetKey(0,"jobId");
1539          if (!cjobId1.Length()) {
1540             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1541             iscalled = kFALSE;
1542             return;
1543          } else {
1544             Info("StartAnalysis", "\n_______________________________________________________________________ \
1545             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1546             \n_______________________________________________________________________",
1547                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1548             jobID += cjobId1;
1549             jobID += " ";
1550             lastmaster = cjobId1.Atoi();
1551             if (!firstmaster) firstmaster = lastmaster;
1552             fNsubmitted++;
1553          }          
1554          delete res;
1555       }   
1556    }
1557    iscalled = kFALSE;
1558 }
1559
1560 //______________________________________________________________________________
1561 void AliAnalysisAlien::WriteAnalysisFile()
1562 {
1563 // Write current analysis manager into the file analysis.root
1564    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1565       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1566       if (!mgr || !mgr->IsInitialized()) {
1567          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1568          return;
1569       }
1570       // Check analysis type
1571       TObject *handler;
1572       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1573       handler = (TObject*)mgr->GetInputEventHandler();
1574       if (handler) {
1575          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1576          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1577       }
1578       TDirectory *cdir = gDirectory;
1579       TFile *file = TFile::Open("analysis.root", "RECREATE");
1580       if (file) {
1581          mgr->Write();
1582          delete file;
1583       }
1584       if (cdir) cdir->cd();
1585       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1586    }   
1587    Bool_t copy = kTRUE;
1588    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1589    if (copy) {
1590       CdWork();
1591       TString workdir = gGrid->GetHomeDirectory();
1592       workdir += fGridWorkingDir;
1593       Info("CreateJDL", "\n#####   Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1594       if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1595       TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1596    }   
1597 }
1598
1599 //______________________________________________________________________________
1600 void AliAnalysisAlien::WriteAnalysisMacro()
1601 {
1602 // Write the analysis macro that will steer the analysis in grid mode.
1603    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1604       ofstream out;
1605       out.open(fAnalysisMacro.Data(), ios::out);
1606       if (!out.good()) {
1607          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1608          return;
1609       }
1610       TString func = fAnalysisMacro;
1611       TString type = "ESD";
1612       TString comment = "// Analysis using ";
1613       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1614       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1615          type = "AOD";
1616          comment += "AOD";
1617       }   
1618       if (type!="AOD" && fFriendChainName!="") {
1619          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1620          return;
1621       }
1622       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1623       else comment += " data";
1624       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1625       func.ReplaceAll(".C", "");
1626       out << "void " << func.Data() << "()" << endl; 
1627       out << "{" << endl;
1628       out << comment.Data() << endl;
1629       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1630       out << "   TStopwatch timer;" << endl;
1631       out << "   timer.Start();" << endl << endl;
1632       out << "// load base root libraries" << endl;
1633       out << "   gSystem->Load(\"libTree\");" << endl;
1634       out << "   gSystem->Load(\"libGeom\");" << endl;
1635       out << "   gSystem->Load(\"libVMC\");" << endl;
1636       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1637       out << "// Load analysis framework libraries" << endl;
1638       if (!fPackages) {
1639          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1640          out << "   gSystem->Load(\"libESD\");" << endl;
1641          out << "   gSystem->Load(\"libAOD\");" << endl;
1642          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1643          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1644          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1645       } else {
1646          TIter next(fPackages);
1647          TObject *obj;
1648          TString pkgname;
1649          Bool_t hasSTEERBase = kFALSE;
1650          Bool_t hasESD = kFALSE;
1651          Bool_t hasAOD = kFALSE;
1652          Bool_t hasANALYSIS = kFALSE;
1653          Bool_t hasANALYSISalice = kFALSE;
1654          Bool_t hasCORRFW = kFALSE;
1655          while ((obj=next())) {
1656             pkgname = obj->GetName();
1657             if (pkgname == "STEERBase" ||
1658                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1659             if (pkgname == "ESD" ||
1660                 pkgname == "ESD.par")       hasESD = kTRUE;
1661             if (pkgname == "AOD" ||
1662                 pkgname == "AOD.par")       hasAOD = kTRUE;
1663             if (pkgname == "ANALYSIS" ||
1664                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1665             if (pkgname == "ANALYSISalice" ||
1666                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1667             if (pkgname == "CORRFW" ||
1668                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1669          }   
1670          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1671          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1672          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1673          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1674          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1675          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1676          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1677          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1678          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1679          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1680          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1681          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1682          out << "// Compile other par packages" << endl;
1683          next.Reset();
1684          while ((obj=next())) {
1685             pkgname = obj->GetName();
1686             if (pkgname == "STEERBase" ||
1687                 pkgname == "STEERBase.par" ||
1688                 pkgname == "ESD" ||
1689                 pkgname == "ESD.par" ||
1690                 pkgname == "AOD" ||
1691                 pkgname == "AOD.par" ||
1692                 pkgname == "ANALYSIS" ||
1693                 pkgname == "ANALYSIS.par" ||
1694                 pkgname == "ANALYSISalice" ||
1695                 pkgname == "ANALYSISalice.par" ||
1696                 pkgname == "CORRFW" ||
1697                 pkgname == "CORRFW.par") continue;
1698             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1699          }   
1700       }   
1701       out << "// include path" << endl;
1702       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1703       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1704       if (fAdditionalLibs.Length()) {
1705          out << "// Add aditional AliRoot libraries" << endl;
1706          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1707          TIter next(list);
1708          TObjString *str;
1709          while((str=(TObjString*)next())) {
1710             if (str->GetString().Contains(".so"))
1711                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1712          }
1713          if (list) delete list;
1714       }
1715       out << endl;
1716       out << "// analysis source to be compiled at runtime (if any)" << endl;
1717       if (fAnalysisSource.Length()) {
1718          TObjArray *list = fAnalysisSource.Tokenize(" ");
1719          TIter next(list);
1720          TObjString *str;
1721          while((str=(TObjString*)next())) {
1722             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1723          }   
1724          if (list) delete list;
1725       }
1726       out << endl;
1727       out << "// connect to AliEn and make the chain" << endl;
1728       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1729       if (IsUsingTags()) {
1730          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1731       } else {
1732          if(fFriendChainName!="AliAOD.VertexingHF.root") {
1733             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
1734          } else {
1735             out << "   // Check if the macro to create the chain was provided" << endl;
1736             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1737             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1738             out << "      return;" << endl;
1739             out << "   }" << endl;
1740             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1741             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1742          }  
1743       }   
1744       out << "// read the analysis manager from file" << endl;
1745       out << "   TFile *file = TFile::Open(\"analysis.root\");" << endl;
1746       out << "   if (!file) return;" << endl; 
1747       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1748       out << "   AliAnalysisManager *mgr = 0;" << endl;
1749       out << "   TKey *key;" << endl;
1750       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1751       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1752       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1753       out << "   };" << endl;
1754       out << "   if (!mgr) {" << endl;
1755       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1756       out << "      return;" << endl;
1757       out << "   }" << endl << endl;
1758       out << "   mgr->PrintStatus();" << endl;
1759       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1760       out << "   timer.Stop();" << endl;
1761       out << "   timer.Print();" << endl;
1762       out << "}" << endl << endl;
1763       if (IsUsingTags()) {
1764          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1765          out << "{" << endl;
1766          out << "// Create a chain using tags from the xml file." << endl;
1767          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1768          out << "   if (!coll) {" << endl;
1769          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1770          out << "      return NULL;" << endl;
1771          out << "   }" << endl;
1772          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1773          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1774          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1775          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1776          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1777          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1778          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1779          out << "   // Check if the cuts configuration file was provided" << endl;
1780          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1781          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1782          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1783          out << "   }" << endl;
1784          if (fFriendChainName=="") {
1785             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1786          } else {
1787             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1788             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1789             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1790          }
1791          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1792          out << "   chain->ls();" << endl;
1793          out << "   return chain;" << endl;
1794          out << "}" << endl << endl;
1795          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1796             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1797             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1798             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1799             msg += "                      AliDetectorTagCuts *detCuts,\n";
1800             msg += "                      AliEventTagCuts *evCuts)";
1801             Info("WriteAnalysisMacro", msg.Data());
1802          }
1803       } 
1804       if (!IsUsingTags() || fFriendChainName!="") {
1805          out <<"//________________________________________________________________________________" << endl;
1806          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1807          out << "{" << endl;
1808          out << "// Create a chain using url's from xml file" << endl;
1809          out << "   TString treename = type;" << endl;
1810          out << "   treename.ToLower();" << endl;
1811          out << "   treename += \"Tree\";" << endl;
1812          out << "   printf(\"***************************************\\n\");" << endl;
1813          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1814          out << "   printf(\"***************************************\\n\");" << endl;
1815          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1816          out << "   if (!coll) {" << endl;
1817          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1818          out << "      return NULL;" << endl;
1819          out << "   }" << endl;
1820          out << "   TChain *chain = new TChain(treename);" << endl;
1821          if(fFriendChainName!="") {
1822             out << "   TChain *chainFriend = new TChain(treename);" << endl;
1823          }
1824          out << "   coll->Reset();" << endl;
1825          out << "   while (coll->Next()) {" << endl;
1826          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
1827          if(fFriendChainName!="") {
1828             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
1829             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1830             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1831             out << "      chainFriend->Add(fileFriend.Data());" << endl;
1832          }
1833          out << "   }" << endl;
1834          out << "   if (!chain->GetNtrees()) {" << endl;
1835          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1836          out << "      return NULL;" << endl;
1837          out << "   }" << endl;
1838          if(fFriendChainName!="") {
1839             out << "   chain->AddFriend(chainFriend);" << endl;
1840          }
1841          out << "   return chain;" << endl;
1842          out << "}" << endl << endl;
1843       }   
1844       if (fPackages) {
1845          out <<"//________________________________________________________________________________" << endl;
1846          out << "Bool_t SetupPar(const char *package) {" << endl;
1847          out << "// Compile the package and set it up." << endl;
1848          out << "   TString pkgdir = package;" << endl;
1849          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1850          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1851          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1852          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1853          out << "   // Check for BUILD.sh and execute" << endl;
1854          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1855          out << "      printf(\"*******************************\\n\");" << endl;
1856          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1857          out << "      printf(\"*******************************\\n\");" << endl;
1858          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1859          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1860          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1861          out << "         return kFALSE;" << endl;
1862          out << "      }" << endl;
1863          out << "   } else {" << endl;
1864          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1865          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1866          out << "      return kFALSE;" << endl;
1867          out << "   }" << endl;
1868          out << "   // Check for SETUP.C and execute" << endl;
1869          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1870          out << "      printf(\"*******************************\\n\");" << endl;
1871          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1872          out << "      printf(\"*******************************\\n\");" << endl;
1873          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1874          out << "   } else {" << endl;
1875          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1876          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1877          out << "      return kFALSE;" << endl;
1878          out << "   }" << endl;
1879          out << "   // Restore original workdir" << endl;
1880          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1881          out << "   return kTRUE;" << endl;
1882          out << "}" << endl;
1883       }
1884       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1885    }   
1886    Bool_t copy = kTRUE;
1887    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1888    if (copy) {
1889       CdWork();
1890       TString workdir = gGrid->GetHomeDirectory();
1891       workdir += fGridWorkingDir;
1892       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1893       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1894          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1895          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1896          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1897       }   
1898       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1899       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1900    }
1901 }
1902
1903 //______________________________________________________________________________
1904 void AliAnalysisAlien::WriteExecutable()
1905 {
1906 // Generate the alien executable script.
1907    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1908       ofstream out;
1909       out.open(fExecutable.Data(), ios::out);
1910       if (out.bad()) {
1911          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
1912          return;
1913       }
1914       out << "#!/bin/bash" << endl;
1915       out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1916       out << "echo \"=========================================\"" << endl; 
1917       out << "echo \"############## PATH : ##############\"" << endl;
1918       out << "echo $PATH" << endl;
1919       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1920       out << "echo $LD_LIBRARY_PATH" << endl;
1921       out << "echo \"############## ROOTSYS : ##############\"" << endl;
1922       out << "echo $ROOTSYS" << endl;
1923       out << "echo \"############## which root : ##############\"" << endl;
1924       out << "which root" << endl;
1925       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1926       out << "echo $ALICE_ROOT" << endl;
1927       out << "echo \"############## which aliroot : ##############\"" << endl;
1928       out << "which aliroot" << endl;
1929       out << "echo \"=========================================\"" << endl << endl;
1930 //      if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1931       out << "root -b -q "; 
1932       out << fAnalysisMacro.Data() << endl << endl;
1933       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1934    }   
1935    Bool_t copy = kTRUE;
1936    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1937    if (copy) {
1938       CdWork();
1939       TString workdir = gGrid->GetHomeDirectory();
1940       workdir += fGridWorkingDir;
1941       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1942       if (FileExists(executable)) gGrid->Rm(executable);
1943       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1944       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1945    } 
1946 }
1947
1948 //______________________________________________________________________________
1949 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
1950 {
1951 // Write the production file to be submitted by LPM manager. The format is:
1952 // First line: full_path_to_jdl estimated_no_subjobs_per_master
1953 // Next lines: full_path_to_dataset XXX (XXX is a string)
1954 // To submit, one has to: submit jdl XXX for all lines
1955    ofstream out;
1956    out.open(filename, ios::out);
1957    if (out.bad()) {
1958       Error("WriteProductionFile", "Bad file name: %s", filename);
1959       return;
1960    }
1961    TString workdir = gGrid->GetHomeDirectory();
1962    workdir += fGridWorkingDir;
1963    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
1964    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1965    out << locjdl << " " << njobspermaster << endl;
1966    Int_t nmasterjobs = fInputFiles->GetEntries();
1967    for (Int_t i=0; i<nmasterjobs; i++) {
1968       out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
1969    }
1970    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
1971    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
1972 }
1973
1974 //______________________________________________________________________________
1975 void AliAnalysisAlien::WriteValidationScript()
1976 {
1977 // Generate the alien validation script.
1978    // Generate the validation script
1979    TObjString *os;
1980    if (!Connect()) {
1981       Error("WriteValidationScript", "Alien connection required");
1982       return;
1983    }
1984    TString out_stream = "";
1985    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1986    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1987       ofstream out;
1988       out.open("validate.sh", ios::out);
1989       out << "#!/bin/bash" << endl;
1990       out << "##################################################" << endl;
1991       out << "validateout=`dirname $0`" << endl;
1992       out << "validatetime=`date`" << endl;
1993       out << "validated=\"0\";" << endl;
1994       out << "error=0" << endl;
1995       out << "if [ -z $validateout ]" << endl;
1996       out << "then" << endl;
1997       out << "    validateout=\".\"" << endl;
1998       out << "fi" << endl << endl;
1999       out << "cd $validateout;" << endl;
2000       out << "validateworkdir=`pwd`;" << endl << endl;
2001       out << "echo \"*******************************************************\"" << out_stream << endl;
2002       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
2003       out << "" << endl;
2004       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
2005       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
2006       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
2007       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2008       out << "ls -la ./"  << out_stream << endl;
2009       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
2010       out << "##################################################" << endl;
2011
2012       out << "" << endl;
2013       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2014       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2015       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2016       out << "" << endl;
2017
2018       out << "if [ ! -f stderr ] ; then" << endl;
2019       out << "   error=1" << endl;
2020       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
2021       out << "   echo \"Error = $error\" " << out_stream << endl;
2022       out << "fi" << endl;
2023
2024       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2025       out << "   error=1" << endl;
2026       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
2027       out << "   echo \"$parArch\" " << out_stream << endl;
2028       out << "   echo \"Error = $error\" " << out_stream << endl;
2029       out << "fi" << endl;
2030
2031       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2032       out << "   error=1" << endl;
2033       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
2034       out << "   echo \"$segViol\" " << out_stream << endl;
2035       out << "   echo \"Error = $error\" " << out_stream << endl;
2036       out << "fi" << endl;
2037
2038       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2039       out << "   error=1" << endl;
2040       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
2041       out << "   echo \"$segFault\" " << out_stream << endl;
2042       out << "   echo \"Error = $error\" " << out_stream << endl;
2043       out << "fi" << endl;
2044
2045       // Part dedicated to the specific analyses running into the train
2046
2047       TObjArray *arr = fOutputFiles.Tokenize(" ");
2048       TIter next1(arr);
2049       TString output_file;
2050       while ((os=(TObjString*)next1())) { 
2051          output_file = os->GetString();
2052          Int_t index = output_file.Index("@");
2053          if (index > 0) output_file.Remove(index);
2054          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2055          out << "   error=1" << endl;
2056          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
2057          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2058          out << "fi" << endl;
2059       }   
2060       delete arr;
2061       out << "if [ $error = 0 ] ; then" << endl;
2062       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
2063       out << "fi" << endl;
2064
2065       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2066       out << "echo \"*******************************************************\""  << out_stream << endl;
2067       out << "cd -" << endl;
2068       out << "exit $error" << endl;
2069    }    
2070    Bool_t copy = kTRUE;
2071    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2072    if (copy) {
2073       CdWork();
2074       TString workdir = gGrid->GetHomeDirectory();
2075       workdir += fGridWorkingDir;
2076       Info("CreateJDL", "\n#####   Copying validation script <validate.sh> to your AliEn working space");
2077       if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
2078       TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
2079    } 
2080 }