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