]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
A fix for being able to compile the par file of ANALYSISalice if requested
[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 "TEnv.h"
25 #include "TError.h"
26 #include "TROOT.h"
27 #include "TSystem.h"
28 #include "TFile.h"
29 #include "TObjString.h"
30 #include "TObjArray.h"
31 #include "TGrid.h"
32 #include "TGridResult.h"
33 #include "TGridCollection.h"
34 #include "TGridJDL.h"
35 #include "TGridJobStatusList.h"
36 #include "TGridJobStatus.h"
37 #include "TFileMerger.h"
38 #include "AliAnalysisManager.h"
39 #include "AliVEventHandler.h"
40 #include "AliAnalysisDataContainer.h"
41 #include "AliAnalysisAlien.h"
42
43 ClassImp(AliAnalysisAlien)
44
45 //______________________________________________________________________________
46 AliAnalysisAlien::AliAnalysisAlien()
47                  :AliAnalysisGrid(),
48                   fGridJDL(NULL),
49                   fMergingJDL(NULL),
50                   fPrice(0),
51                   fTTL(0),
52                   fSplitMaxInputFileNumber(0),
53                   fMaxInitFailed(0),
54                   fMasterResubmitThreshold(0),
55                   fNtestFiles(0),
56                   fNrunsPerMaster(0),
57                   fMaxMergeFiles(0),
58                   fNsubmitted(0),
59                   fProductionMode(0),
60                   fOutputToRunNo(0),
61                   fMergeViaJDL(0),
62                   fFastReadOption(0),
63                   fOverwriteMode(0),
64                   fRunNumbers(),
65                   fExecutable(),
66                   fExecutableCommand(),
67                   fArguments(),
68                   fExecutableArgs(),
69                   fAnalysisMacro(),
70                   fAnalysisSource(),
71                   fAdditionalRootLibs(),
72                   fAdditionalLibs(),
73                   fSplitMode(),
74                   fAPIVersion(),
75                   fROOTVersion(),
76                   fAliROOTVersion(),
77                   fExternalPackages(),
78                   fUser(),
79                   fGridWorkingDir(),
80                   fGridDataDir(),
81                   fDataPattern(),
82                   fGridOutputDir(),
83                   fOutputArchive(),
84                   fOutputFiles(),
85                   fInputFormat(),
86                   fDatasetName(),
87                   fJDLName(),
88                             fMergeExcludes(),
89                   fIncludePath(),
90                   fCloseSE(),
91                   fFriendChainName(),
92                   fJobTag(),
93                   fOutputSingle(),
94                   fRunPrefix(),
95                   fInputFiles(0),
96                   fPackages(0)
97 {
98 // Dummy ctor.
99    SetDefaults();
100 }
101
102 //______________________________________________________________________________
103 AliAnalysisAlien::AliAnalysisAlien(const char *name)
104                  :AliAnalysisGrid(name),
105                   fGridJDL(NULL),
106                   fMergingJDL(NULL),
107                   fPrice(0),
108                   fTTL(0),
109                   fSplitMaxInputFileNumber(0),
110                   fMaxInitFailed(0),
111                   fMasterResubmitThreshold(0),
112                   fNtestFiles(0),
113                   fNrunsPerMaster(0),
114                   fMaxMergeFiles(0),
115                   fNsubmitted(0),
116                   fProductionMode(0),
117                   fOutputToRunNo(0),
118                   fMergeViaJDL(0),
119                   fFastReadOption(0),
120                   fOverwriteMode(0),
121                   fRunNumbers(),
122                   fExecutable(),
123                   fExecutableCommand(),
124                   fArguments(),
125                   fExecutableArgs(),
126                   fAnalysisMacro(),
127                   fAnalysisSource(),
128                   fAdditionalRootLibs(),
129                   fAdditionalLibs(),
130                   fSplitMode(),
131                   fAPIVersion(),
132                   fROOTVersion(),
133                   fAliROOTVersion(),
134                   fExternalPackages(),
135                   fUser(),
136                   fGridWorkingDir(),
137                   fGridDataDir(),
138                   fDataPattern(),
139                   fGridOutputDir(),
140                   fOutputArchive(),
141                   fOutputFiles(),
142                   fInputFormat(),
143                   fDatasetName(),
144                   fJDLName(),
145                   fMergeExcludes(),
146                   fIncludePath(),
147                   fCloseSE(),
148                   fFriendChainName(),
149                   fJobTag(),
150                   fOutputSingle(),
151                   fRunPrefix(),
152                   fInputFiles(0),
153                   fPackages(0)
154 {
155 // Default ctor.
156    SetDefaults();
157 }
158
159 //______________________________________________________________________________
160 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
161                  :AliAnalysisGrid(other),
162                   fGridJDL(NULL),
163                   fMergingJDL(NULL),
164                   fPrice(other.fPrice),
165                   fTTL(other.fTTL),
166                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
167                   fMaxInitFailed(other.fMaxInitFailed),
168                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
169                   fNtestFiles(other.fNtestFiles),
170                   fNrunsPerMaster(other.fNrunsPerMaster),
171                   fMaxMergeFiles(other.fMaxMergeFiles),
172                   fNsubmitted(other.fNsubmitted),
173                   fProductionMode(other.fProductionMode),
174                   fOutputToRunNo(other.fOutputToRunNo),
175                   fMergeViaJDL(other.fMergeViaJDL),
176                   fFastReadOption(other.fFastReadOption),
177                   fOverwriteMode(other.fOverwriteMode),
178                   fRunNumbers(other.fRunNumbers),
179                   fExecutable(other.fExecutable),
180                   fExecutableCommand(other.fExecutableCommand),
181                   fArguments(other.fArguments),
182                   fExecutableArgs(other.fExecutableArgs),
183                   fAnalysisMacro(other.fAnalysisMacro),
184                   fAnalysisSource(other.fAnalysisSource),
185                   fAdditionalRootLibs(other.fAdditionalRootLibs),
186                   fAdditionalLibs(other.fAdditionalLibs),
187                   fSplitMode(other.fSplitMode),
188                   fAPIVersion(other.fAPIVersion),
189                   fROOTVersion(other.fROOTVersion),
190                   fAliROOTVersion(other.fAliROOTVersion),
191                   fExternalPackages(other.fExternalPackages),
192                   fUser(other.fUser),
193                   fGridWorkingDir(other.fGridWorkingDir),
194                   fGridDataDir(other.fGridDataDir),
195                   fDataPattern(other.fDataPattern),
196                   fGridOutputDir(other.fGridOutputDir),
197                   fOutputArchive(other.fOutputArchive),
198                   fOutputFiles(other.fOutputFiles),
199                   fInputFormat(other.fInputFormat),
200                   fDatasetName(other.fDatasetName),
201                   fJDLName(other.fJDLName),
202                   fMergeExcludes(other.fMergeExcludes),
203                   fIncludePath(other.fIncludePath),
204                   fCloseSE(other.fCloseSE),
205                   fFriendChainName(other.fFriendChainName),
206                   fJobTag(other.fJobTag),
207                   fOutputSingle(other.fOutputSingle),
208                   fRunPrefix(other.fRunPrefix),
209                   fInputFiles(0),
210                   fPackages(0)
211 {
212 // Copy ctor.
213    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
214    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
215    fRunRange[0] = other.fRunRange[0];
216    fRunRange[1] = other.fRunRange[1];
217    if (other.fInputFiles) {
218       fInputFiles = new TObjArray();
219       TIter next(other.fInputFiles);
220       TObject *obj;
221       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
222       fInputFiles->SetOwner();
223    }   
224    if (other.fPackages) {
225       fPackages = new TObjArray();
226       TIter next(other.fPackages);
227       TObject *obj;
228       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
229       fPackages->SetOwner();
230    }   
231 }
232
233 //______________________________________________________________________________
234 AliAnalysisAlien::~AliAnalysisAlien()
235 {
236 // Destructor.
237    if (fGridJDL) delete fGridJDL;
238    if (fMergingJDL) delete fMergingJDL;
239    if (fInputFiles) delete fInputFiles;
240    if (fPackages) delete fPackages;
241 }   
242
243 //______________________________________________________________________________
244 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
245 {
246 // Assignment.
247    if (this != &other) {
248       AliAnalysisGrid::operator=(other);
249       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
250       fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
251       fPrice                   = other.fPrice;
252       fTTL                     = other.fTTL;
253       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
254       fMaxInitFailed           = other.fMaxInitFailed;
255       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
256       fNtestFiles              = other.fNtestFiles;
257       fNrunsPerMaster          = other.fNrunsPerMaster;
258       fMaxMergeFiles           = other.fMaxMergeFiles;
259       fNsubmitted              = other.fNsubmitted;
260       fProductionMode          = other.fProductionMode;
261       fOutputToRunNo           = other.fOutputToRunNo;
262       fMergeViaJDL             = other.fMergeViaJDL;
263       fFastReadOption          = other.fFastReadOption;
264       fOverwriteMode           = other.fOverwriteMode;
265       fRunNumbers              = other.fRunNumbers;
266       fExecutable              = other.fExecutable;
267       fExecutableCommand       = other.fExecutableCommand;
268       fArguments               = other.fArguments;
269       fExecutableArgs          = other.fExecutableArgs;
270       fAnalysisMacro           = other.fAnalysisMacro;
271       fAnalysisSource          = other.fAnalysisSource;
272       fAdditionalRootLibs      = other.fAdditionalRootLibs;
273       fAdditionalLibs          = other.fAdditionalLibs;
274       fSplitMode               = other.fSplitMode;
275       fAPIVersion              = other.fAPIVersion;
276       fROOTVersion             = other.fROOTVersion;
277       fAliROOTVersion          = other.fAliROOTVersion;
278       fExternalPackages        = other.fExternalPackages;
279       fUser                    = other.fUser;
280       fGridWorkingDir          = other.fGridWorkingDir;
281       fGridDataDir             = other.fGridDataDir;
282       fDataPattern             = other.fDataPattern;
283       fGridOutputDir           = other.fGridOutputDir;
284       fOutputArchive           = other.fOutputArchive;
285       fOutputFiles             = other.fOutputFiles;
286       fInputFormat             = other.fInputFormat;
287       fDatasetName             = other.fDatasetName;
288       fJDLName                 = other.fJDLName;
289       fMergeExcludes           = other.fMergeExcludes;
290       fIncludePath             = other.fIncludePath;
291       fCloseSE                 = other.fCloseSE;
292       fFriendChainName         = other.fFriendChainName;
293       fJobTag                  = other.fJobTag;
294       fOutputSingle            = other.fOutputSingle;
295       fRunPrefix               = other.fRunPrefix;
296       if (other.fInputFiles) {
297          fInputFiles = new TObjArray();
298          TIter next(other.fInputFiles);
299          TObject *obj;
300          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
301          fInputFiles->SetOwner();
302       }   
303       if (other.fPackages) {
304          fPackages = new TObjArray();
305          TIter next(other.fPackages);
306          TObject *obj;
307          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
308          fPackages->SetOwner();
309       }   
310    }
311    return *this;
312 }
313
314 //______________________________________________________________________________
315 void AliAnalysisAlien::AddIncludePath(const char *path)
316 {
317 // Add include path in the remote analysis macro.
318    TString p(path);
319    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
320    else                  fIncludePath += Form("-I%s ", path);
321 }
322
323 //______________________________________________________________________________
324 void AliAnalysisAlien::AddRunNumber(Int_t run)
325 {
326 // Add a run number to the list of runs to be processed.
327    if (fRunNumbers.Length()) fRunNumbers += " ";
328    fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
329 }   
330
331 //______________________________________________________________________________
332 void AliAnalysisAlien::AddRunNumber(const char* run)
333 {
334 // Add a run number to the list of runs to be processed.
335    if (fRunNumbers.Length()) fRunNumbers += " ";
336    fRunNumbers += run;
337 }   
338
339 //______________________________________________________________________________
340 void AliAnalysisAlien::AddDataFile(const char *lfn)
341 {
342 // Adds a data file to the input to be analysed. The file should be a valid LFN
343 // or point to an existing file in the alien workdir.
344    if (!fInputFiles) fInputFiles = new TObjArray();
345    fInputFiles->Add(new TObjString(lfn));
346 }
347
348 //______________________________________________________________________________
349 void AliAnalysisAlien::AddExternalPackage(const char *package)
350 {
351 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
352    if (fExternalPackages) fExternalPackages += " ";
353    fExternalPackages += package;
354 }   
355       
356 //______________________________________________________________________________
357 Bool_t AliAnalysisAlien::Connect()
358 {
359 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
360    if (gGrid && gGrid->IsConnected()) return kTRUE;
361    if (!gSystem->Getenv("alien_API_USER")) {
362       Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
363             gSystem->Getenv("UID"));
364       return kFALSE;
365    }         
366    if (!gGrid) {
367       Info("Connect", "Trying to connect to AliEn ...");
368       TGrid::Connect("alien://");
369    }
370    if (!gGrid || !gGrid->IsConnected()) {
371       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
372       return kFALSE;
373    }  
374    fUser = gGrid->GetUser();
375    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
376    return kTRUE;
377 }
378
379 //______________________________________________________________________________
380 void AliAnalysisAlien::CdWork()
381 {
382 // Check validity of alien workspace. Create directory if possible.
383    if (!Connect()) {
384       Error("CdWork", "Alien connection required");
385       return;
386    } 
387    TString homedir = gGrid->GetHomeDirectory();
388    TString workdir = homedir + fGridWorkingDir;
389    if (DirectoryExists(workdir)) {
390       gGrid->Cd(workdir);
391       return;
392    }   
393    // Work directory not existing - create it
394    gGrid->Cd(homedir);
395    if (gGrid->Mkdir(workdir)) {
396       gGrid->Cd(fGridWorkingDir);
397       Info("CreateJDL", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
398    } else {
399       Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
400               workdir.Data(), homedir.Data());
401       fGridWorkingDir = "";
402    }          
403 }
404
405 //______________________________________________________________________________
406 Bool_t AliAnalysisAlien::CheckInputData()
407 {
408 // Check validity of input data. If necessary, create xml files.
409    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
410       if (!fGridDataDir.Length()) {
411          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
412          return kFALSE;
413       }
414       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
415       return kTRUE;
416    }
417    // Process declared files
418    Bool_t is_collection = kFALSE;
419    Bool_t is_xml = kFALSE;
420    Bool_t use_tags = kFALSE;
421    Bool_t checked = kFALSE;
422    CdWork();
423    TString file;
424    TString workdir = gGrid->GetHomeDirectory();
425    workdir += fGridWorkingDir;
426    if (fInputFiles) {
427       TObjString *objstr;
428       TIter next(fInputFiles);
429       while ((objstr=(TObjString*)next())) {
430          file = workdir;
431          file += "/";
432          file += objstr->GetString();
433          // Store full lfn path
434          if (FileExists(file)) objstr->SetString(file);
435          else {
436             file = objstr->GetName();
437             if (!FileExists(objstr->GetName())) {
438                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
439                      objstr->GetName(), workdir.Data());
440                return kFALSE;
441             }         
442          }
443          Bool_t iscoll, isxml, usetags;
444          CheckDataType(file, iscoll, isxml, usetags);
445          if (!checked) {
446             checked = kTRUE;
447             is_collection = iscoll;
448             is_xml = isxml;
449             use_tags = usetags;
450             TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
451          } else {
452             if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
453                Error("CheckInputData", "Some conflict was found in the types of inputs");
454                return kFALSE;
455             } 
456          }
457       }
458    }
459    // Process requested run numbers
460    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
461    // Check validity of alien data directory
462    if (!fGridDataDir.Length()) {
463       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
464       return kFALSE;
465    }
466    if (!DirectoryExists(fGridDataDir)) {
467       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
468       return kFALSE;
469    }
470    if (is_collection) {
471       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
472       return kFALSE;   
473    }
474    
475    if (checked && !is_xml) {
476       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
477       return kFALSE;   
478    }
479    // Check validity of run number(s)
480    TObjArray *arr;
481    TObjString *os;
482    Int_t nruns = 0;
483    TString schunk, schunk2;
484    TString path;
485    if (!checked) {
486       checked = kTRUE;
487       use_tags = fDataPattern.Contains("tag");
488       TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
489    }   
490    if (use_tags != fDataPattern.Contains("tag")) {
491       Error("CheckInputData", "Cannot mix input files using/not using tags");
492       return kFALSE;
493    }
494    if (fRunNumbers.Length()) {
495       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
496       arr = fRunNumbers.Tokenize(" ");
497       TIter next(arr);
498       while ((os=(TObjString*)next())) {
499          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
500          if (!DirectoryExists(path)) {
501             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
502             continue;
503          }
504          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
505          TString msg = "\n#####   file: ";
506          msg += path;
507          msg += " type: xml_collection;";
508          if (use_tags) msg += " using_tags: Yes";
509          else          msg += " using_tags: No";
510          Info("CheckDataType", msg.Data());
511          if (fNrunsPerMaster<2) {
512             AddDataFile(Form("%s.xml", os->GetString().Data()));
513          } else {
514             nruns++;
515             if (((nruns-1)%fNrunsPerMaster) == 0) {
516                schunk = os->GetString();
517             }   
518             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
519             schunk += Form("_%s.xml", os->GetString().Data());
520             AddDataFile(schunk);
521          }   
522       }
523       delete arr;   
524    } else {
525       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
526       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
527          path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
528          if (!DirectoryExists(path)) {
529 //            Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
530             continue;
531          }
532          path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
533          TString msg = "\n#####   file: ";
534          msg += path;
535          msg += " type: xml_collection;";
536          if (use_tags) msg += " using_tags: Yes";
537          else          msg += " using_tags: No";
538          Info("CheckDataType", msg.Data());
539          if (fNrunsPerMaster<2) {
540             AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
541          } else {
542             nruns++;
543             if (((nruns-1)%fNrunsPerMaster) == 0) {
544                schunk = Form("%s%d", fRunPrefix.Data(),irun);
545             }
546             schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
547             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
548             schunk += schunk2;
549             AddDataFile(schunk);
550          }   
551       }
552       if (!fInputFiles) {
553          schunk += schunk2;
554          AddDataFile(schunk);
555       }   
556    }
557    return kTRUE;      
558 }   
559
560 //______________________________________________________________________________
561 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
562 {
563 // Create dataset for the grid data directory + run number.
564    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
565    if (!Connect()) {
566       Error("CreateDataset", "Cannot create dataset with no grid connection");
567       return kFALSE;
568    }   
569
570    // Cd workspace
571    CdWork();
572    TString workdir = gGrid->GetHomeDirectory();
573    workdir += fGridWorkingDir;
574
575    // Compose the 'find' command arguments
576    TString command;
577    TString options = "-x collection ";
578    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
579    TString conditions = "";
580    
581    TString file;
582    TString path;
583    Int_t nruns = 0;
584    TString schunk, schunk2;
585    TGridCollection *cbase=0, *cadd=0;
586    if (!fRunNumbers.Length() && !fRunRange[0]) {
587       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
588       // Make a single data collection from data directory.
589       path = fGridDataDir;
590       if (!DirectoryExists(path)) {
591          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
592          return kFALSE;
593       }   
594 //      CdWork();
595       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
596       else file = Form("%s.xml", gSystem->BaseName(path));
597       if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
598          command = "find ";
599          command += options;
600          command += path;
601          command += " ";
602          command += pattern;
603          command += conditions;
604          printf("command: %s\n", command.Data());
605          TGridResult *res = gGrid->Command(command);
606          if (res) delete res;
607          // Write standard output to file
608          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
609       }
610       Bool_t fileExists = FileExists(file);
611       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
612          // Copy xml file to alien space
613          if (fileExists) gGrid->Rm(file);
614          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
615          if (!FileExists(file)) {
616             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
617             return kFALSE;
618          }
619          // Update list of files to be processed.
620       }
621       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
622       return kTRUE;
623    }   
624    // Several runs
625    if (fRunNumbers.Length()) {
626       TObjArray *arr = fRunNumbers.Tokenize(" ");
627       TObjString *os;
628       TIter next(arr);
629       while ((os=(TObjString*)next())) {
630          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
631          if (!DirectoryExists(path)) continue;
632 //         CdWork();
633          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
634          else file = Form("%s.xml", os->GetString().Data());
635          // If local collection file does not exist, create it via 'find' command.
636          if (gSystem->AccessPathName(file)) {
637             command = "find ";
638             command += options;
639             command += path;
640             command += pattern;
641             command += conditions;
642             TGridResult *res = gGrid->Command(command);
643             if (res) delete res;
644             // Write standard output to file
645             gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
646          }   
647          if (TestBit(AliAnalysisGrid::kTest)) break;
648          // Check if there is one run per master job.
649          if (fNrunsPerMaster<2) {
650             if (FileExists(file)) {
651                if (fOverwriteMode) gGrid->Rm(file);
652                else {
653                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
654                   continue;
655                }   
656             }        
657             // Copy xml file to alien space
658             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
659             if (!FileExists(file)) {
660                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
661                delete arr;
662                return kFALSE;
663             }
664          } else {
665             nruns++;
666             if (((nruns-1)%fNrunsPerMaster) == 0) {
667                schunk = os->GetString();
668                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
669             } else {
670                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
671                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
672                cbase->Add(cadd);
673                delete cadd;
674             }
675             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
676                continue;
677             }   
678             schunk += Form("_%s.xml", os->GetString().Data());
679             if (FileExists(schunk)) {               
680                if (fOverwriteMode) gGrid->Rm(file);
681                else {
682                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
683                   continue;
684                }   
685             }        
686             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
687             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
688             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
689             if (!FileExists(schunk)) {
690                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
691                delete arr;
692                return kFALSE;
693             }
694          }   
695       }   
696       delete arr;
697    } else {
698       // Process a full run range.
699       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
700          path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
701          if (!DirectoryExists(path)) continue;
702 //         CdWork();
703          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
704          else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
705          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
706             if (fOverwriteMode) gGrid->Rm(file);
707             else {
708                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
709                continue;
710             }   
711          }
712          // If local collection file does not exist, create it via 'find' command.
713          if (gSystem->AccessPathName(file) || fOverwriteMode) {
714             command = "find ";
715             command += options;
716             command += path;
717             command += pattern;
718             command += conditions;
719             TGridResult *res = gGrid->Command(command);
720             if (res) delete res;
721             // Write standard output to file
722             gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
723          }   
724          if (TestBit(AliAnalysisGrid::kTest)) break;
725          // Check if there is one run per master job.
726          if (fNrunsPerMaster<2) {
727             if (FileExists(file)) {
728                if (fOverwriteMode) gGrid->Rm(file);
729                else {
730                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
731                   continue;
732                }   
733             }        
734             // Copy xml file to alien space
735             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
736             if (!FileExists(file)) {
737                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
738                return kFALSE;
739             }
740          } else {
741             nruns++;
742             // Check if the collection for the chunk exist locally.
743             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
744             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
745                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
746                else continue;
747             }   
748             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
749             if (((nruns-1)%fNrunsPerMaster) == 0) {
750                schunk = Form("%s%d", fRunPrefix.Data(), irun);
751                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
752             } else {
753                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
754                cbase->Add(cadd);
755                delete cadd;
756             }
757             schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
758             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
759                continue;
760             }   
761             schunk = schunk2;
762             if (FileExists(schunk)) {
763                if (fOverwriteMode) gGrid->Rm(schunk);
764                else {
765                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
766                   continue;
767                }   
768             }        
769             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
770             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
771             if (FileExists(schunk)) {
772                if (fOverwriteMode) gGrid->Rm(schunk);
773                else {
774                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
775                   continue;
776                }   
777             }   
778             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
779             if (!FileExists(schunk)) {
780                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
781                return kFALSE;
782             }
783          }   
784       }
785    }      
786    return kTRUE;
787 }
788
789 //______________________________________________________________________________
790 Bool_t AliAnalysisAlien::CreateJDL()
791 {
792 // Generate a JDL file according to current settings. The name of the file is 
793 // specified by fJDLName.
794    Bool_t error = kFALSE;
795    TObjArray *arr = 0;
796    Bool_t copy = kTRUE;
797    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
798    Bool_t generate = kTRUE;
799    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
800    if (!Connect()) {
801       Error("CreateJDL", "Alien connection required");
802       return kFALSE;
803    }   
804    // Check validity of alien workspace
805    CdWork();
806    TString workdir = gGrid->GetHomeDirectory();
807    workdir += fGridWorkingDir;
808    if (generate) {
809       TObjString *os;
810       if (!fInputFiles) {
811          Error("CreateJDL()", "Define some input files for your analysis.");
812          error = kTRUE;
813       }
814       // Compose list of input files   
815       // Check if output files were defined
816       if (!fOutputFiles.Length()) {
817          Error("CreateJDL", "You must define at least one output file");
818          error = kTRUE;
819       }   
820       // Check if an output directory was defined and valid
821       if (!fGridOutputDir.Length()) {
822          Error("CreateJDL", "You must define AliEn output directory");
823          error = kTRUE;
824       } else {
825          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
826          if (!DirectoryExists(fGridOutputDir)) {
827             if (gGrid->Mkdir(fGridOutputDir)) {
828                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
829             } else {
830                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
831                // error = kTRUE;
832             }
833          }
834          gGrid->Cd(workdir);
835       }   
836       // Exit if any error up to now
837       if (error) return kFALSE;   
838       // Set JDL fields
839       if (!fUser.IsNull()) {
840          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
841          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
842       }   
843       fGridJDL->SetExecutable(fExecutable, "This is the startup script");
844       TString mergeExec = fExecutable;
845       mergeExec.ReplaceAll(".sh", "_merge.sh");
846       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
847       mergeExec.ReplaceAll(".sh", ".C");
848       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
849       if (!fArguments.IsNull())
850          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
851       fMergingJDL->SetArguments("$1");   
852       fGridJDL->SetTTL((UInt_t)fTTL);
853       fMergingJDL->SetTTL((UInt_t)fTTL);
854       if (fMaxInitFailed > 0) {
855          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
856          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
857       }   
858       if (fSplitMaxInputFileNumber > 0) {
859          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
860          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
861       }   
862       if (fSplitMode.Length()) {
863          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
864          fGridJDL->SetDescription("Split", "We split per SE or file");
865       }   
866       if (!fAliROOTVersion.IsNull()) {
867          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
868          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
869       }   
870       if (!fROOTVersion.IsNull()) {
871          fGridJDL->AddToPackages("ROOT", fROOTVersion);
872          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
873       }   
874       if (!fAPIVersion.IsNull()) {
875          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
876          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
877       }   
878       if (!fExternalPackages.IsNull()) {
879          arr = fExternalPackages.Tokenize(" ");
880          TIter next(arr);
881          while ((os=(TObjString*)next())) {
882             TString pkgname = os->GetString();
883             Int_t index = pkgname.Index("::");
884             TString pkgversion = pkgname(index+2, pkgname.Length());
885             pkgname.Remove(index);
886             fGridJDL->AddToPackages(pkgname, pkgversion);
887             fMergingJDL->AddToPackages(pkgname, pkgversion);
888          }   
889          delete arr;   
890       }   
891       fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
892       fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
893       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
894       TString analysisFile = fExecutable;
895       analysisFile.ReplaceAll(".sh", ".root");
896       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
897       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
898          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
899       if (fAdditionalLibs.Length()) {
900          arr = fAdditionalLibs.Tokenize(" ");
901          TIter next(arr);
902          while ((os=(TObjString*)next())) {
903             if (os->GetString().Contains(".so")) continue;
904             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
905             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
906          }   
907          delete arr;   
908       }
909       if (fPackages) {
910          TIter next(fPackages);
911          TObject *obj;
912          while ((obj=next())) {
913             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
914             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
915          }
916       }
917       if (fOutputArchive.Length()) {
918          arr = fOutputArchive.Tokenize(" ");
919          TIter next(arr);
920          Bool_t first = kTRUE;
921          const char *comment = "Files to be archived";
922          const char *comment1 = comment;
923          while ((os=(TObjString*)next())) {
924             if (!first) comment = NULL;
925             if (!os->GetString().Contains("@") && fCloseSE.Length())
926                fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
927             else
928                fGridJDL->AddToOutputArchive(os->GetString(), comment);
929             first = kFALSE;   
930          }      
931          delete arr;
932          TString outputArchive = fOutputArchive;
933          if (!fMergeExcludes.IsNull()) {
934             arr = fMergeExcludes.Tokenize(" ");
935             TIter next1(arr);
936             while ((os=(TObjString*)next1())) {
937                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
938                outputArchive.ReplaceAll(os->GetString(),"");
939             }
940             delete arr;
941          }
942          arr = outputArchive.Tokenize(" ");
943          TIter next2(arr);
944          comment = comment1;
945          first = kTRUE;
946          while ((os=(TObjString*)next2())) {
947             if (!first) comment = NULL;
948             if (!os->GetString().Contains("@") && fCloseSE.Length())
949                fMergingJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
950             else
951                fMergingJDL->AddToOutputArchive(os->GetString(), comment);
952             first = kFALSE;   
953          }      
954          delete arr;         
955       }      
956       arr = fOutputFiles.Tokenize(" ");
957       TIter next(arr);
958       Bool_t first = kTRUE;
959       const char *comment = "Files to be archived";
960       const char *comment1 = comment;
961       while ((os=(TObjString*)next())) {
962          // Ignore ouputs in jdl that are also in outputarchive
963          TString sout = os->GetString();
964          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
965          if (fOutputArchive.Contains(sout)) continue;
966          if (!first) comment = NULL;
967          if (!os->GetString().Contains("@") && fCloseSE.Length())
968             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
969          else
970             fGridJDL->AddToOutputSandbox(os->GetString(), comment);
971          first = kFALSE;   
972       }   
973       delete arr;
974       if (fOutputFiles.Length()) {
975          TString outputFiles = fOutputFiles;
976          if (!fMergeExcludes.IsNull()) {
977             arr = fMergeExcludes.Tokenize(" ");
978             TIter next1(arr);
979             while ((os=(TObjString*)next1())) {
980                outputFiles.ReplaceAll(Form("%s,",os->GetString().Data()),"");
981                outputFiles.ReplaceAll(os->GetString(),"");
982             }
983             delete arr;
984          }
985          arr = outputFiles.Tokenize(" ");
986          TIter next2(arr);
987          comment = comment1;
988          first = kTRUE;
989          while ((os=(TObjString*)next2())) {
990             // Ignore ouputs in jdl that are also in outputarchive
991             TString sout = os->GetString();
992             if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
993             if (fOutputArchive.Contains(sout)) continue;
994             if (!first) comment = NULL;
995             if (!os->GetString().Contains("@") && fCloseSE.Length())
996                fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
997             else
998                fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
999          }   
1000          delete arr;
1001       }
1002       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1003       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1004       TString validationScript = fExecutable;
1005       validationScript.ReplaceAll(".sh", "_validation.sh");
1006       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1007       validationScript = fExecutable;
1008       validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
1009       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1010       if (fMasterResubmitThreshold) {
1011          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1012          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1013       }   
1014       // Write a jdl with 2 input parameters: collection name and output dir name.
1015       WriteJDL(copy);
1016    }
1017    // Copy jdl to grid workspace   
1018    if (copy) {
1019       // Check if an output directory was defined and valid
1020       if (!fGridOutputDir.Length()) {
1021          Error("CreateJDL", "You must define AliEn output directory");
1022          return kFALSE;
1023       } else {
1024          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1025          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1026             if (gGrid->Mkdir(fGridOutputDir)) {
1027                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1028             } else {
1029                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1030                return kFALSE;
1031             }
1032          }
1033          gGrid->Cd(workdir);
1034       }   
1035       if (TestBit(AliAnalysisGrid::kSubmit)) {
1036          TString mergeJDLName = fExecutable;
1037          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1038          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1039          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1040          if (fProductionMode) {
1041             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1042             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1043          }   
1044          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1045          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1046          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1047          TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1048          if (fMergeViaJDL) {
1049             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1050             TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1051          }   
1052       }
1053       if (fAdditionalLibs.Length()) {
1054          arr = fAdditionalLibs.Tokenize(" ");
1055          TObjString *os;
1056          TIter next(arr);
1057          while ((os=(TObjString*)next())) {
1058             if (os->GetString().Contains(".so")) continue;
1059             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1060             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1061             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1062          }   
1063          delete arr;   
1064       }
1065       if (fPackages) {
1066          TIter next(fPackages);
1067          TObject *obj;
1068          while ((obj=next())) {
1069             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1070             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1071             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1072          }   
1073       }      
1074    } 
1075    return kTRUE;
1076 }
1077
1078 //______________________________________________________________________________
1079 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1080 {
1081 // Writes one or more JDL's corresponding to findex. If findex is negative,
1082 // all run numbers are considered in one go (jdl). For non-negative indices
1083 // they correspond to the indices in the array fInputFiles.
1084    if (!fInputFiles) return kFALSE;
1085    TObjString *os;
1086    TString workdir = gGrid->GetHomeDirectory();
1087    workdir += fGridWorkingDir;
1088    
1089    if (!fRunNumbers.Length() && !fRunRange[0]) {
1090       // One jdl with no parameters in case input data is specified by name.
1091       TIter next(fInputFiles);
1092       while ((os=(TObjString*)next()))
1093          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()), "Input xml collections");
1094       if (!fOutputSingle.IsNull())
1095          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1096       else {
1097          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1098          fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1099       }   
1100    } else {
1101       // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1102       fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1103       if (!fOutputSingle.IsNull()) {
1104          if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1105          else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1106       } else {   
1107          fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1108          fMergingJDL->SetOutputDirectory(Form("%s/$1", fGridOutputDir.Data()), "Output directory");
1109       }   
1110    }
1111       
1112
1113    // Generate the JDL as a string
1114    TString sjdl = fGridJDL->Generate();
1115    TString sjdl1 = fMergingJDL->Generate();
1116    Int_t index;
1117    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
1118    sjdl.ReplaceAll("(member", "\n   (member");
1119    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1120    sjdl.ReplaceAll("{", "{\n   ");
1121    sjdl.ReplaceAll("};", "\n};");
1122    sjdl.ReplaceAll("{\n   \n", "{\n");
1123    sjdl.ReplaceAll("\n\n", "\n");
1124    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1125    sjdl1.ReplaceAll("\"LF:", "\n   \"LF:");
1126    sjdl1.ReplaceAll("(member", "\n   (member");
1127    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1128    sjdl1.ReplaceAll("{", "{\n   ");
1129    sjdl1.ReplaceAll("};", "\n};");
1130    sjdl1.ReplaceAll("{\n   \n", "{\n");
1131    sjdl1.ReplaceAll("\n\n", "\n");
1132    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1133    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1134    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
1135    index = sjdl.Index("JDLVariables");
1136    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1137    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1138    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:Merging_%s\"\n};\n", fJobTag.Data()));
1139    index = sjdl1.Index("JDLVariables");
1140    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1141    // Write jdl to file
1142    ofstream out;
1143    out.open(fJDLName.Data(), ios::out);
1144    if (out.bad()) {
1145       Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1146       return kFALSE;
1147    }
1148    out << sjdl << endl;
1149    TString mergeJDLName = fExecutable;
1150    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1151    if (fMergeViaJDL) {
1152       ofstream out1;
1153       out1.open(mergeJDLName.Data(), ios::out);
1154       if (out.bad()) {
1155          Error("CreateJDL", "Bad file name: %s", mergeJDLName.Data());
1156          return kFALSE;
1157       }
1158       out1 << sjdl1 << endl;
1159    }   
1160
1161    // Copy jdl to grid workspace   
1162    if (!copy) {
1163       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1164    } else {
1165       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1166       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1167       if (fProductionMode) {
1168          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1169          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1170       }   
1171       if (FileExists(locjdl)) gGrid->Rm(locjdl);
1172       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1173       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1174       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1175       if (fMergeViaJDL) {
1176          Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1177          TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1178       }   
1179    } 
1180    return kTRUE;
1181 }
1182
1183 //______________________________________________________________________________
1184 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1185 {
1186 // Returns true if file exists.
1187    if (!gGrid) return kFALSE;
1188    TGridResult *res = gGrid->Ls(lfn);
1189    if (!res) return kFALSE;
1190    TMap *map = dynamic_cast<TMap*>(res->At(0));
1191    if (!map) {
1192       delete res;
1193       return kFALSE;
1194    }   
1195    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1196    if (!objs || !objs->GetString().Length()) {
1197       delete res;
1198       return kFALSE;
1199    }
1200    delete res;   
1201    return kTRUE;
1202 }
1203
1204 //______________________________________________________________________________
1205 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1206 {
1207 // Returns true if directory exists. Can be also a path.
1208    if (!gGrid) return kFALSE;
1209    // Check if dirname is a path
1210    TString dirstripped = dirname;
1211    dirstripped = dirstripped.Strip();
1212    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1213    TString dir = gSystem->BaseName(dirstripped);
1214    dir += "/";
1215    TString path = gSystem->DirName(dirstripped);
1216    TGridResult *res = gGrid->Ls(path, "-F");
1217    if (!res) return kFALSE;
1218    TIter next(res);
1219    TMap *map;
1220    TObject *obj;
1221    while ((map=dynamic_cast<TMap*>(next()))) {
1222       obj = map->GetValue("name");
1223       if (!obj) break;
1224       if (dir == obj->GetName()) {
1225          delete res;
1226          return kTRUE;
1227       }
1228    }
1229    delete res;
1230    return kFALSE;
1231 }      
1232
1233 //______________________________________________________________________________
1234 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1235 {
1236 // Check input data type.
1237    is_collection = kFALSE;
1238    is_xml = kFALSE;
1239    use_tags = kFALSE;
1240    if (!gGrid) {
1241       Error("CheckDataType", "No connection to grid");
1242       return;
1243    }
1244    is_collection = IsCollection(lfn);
1245    TString msg = "\n#####   file: ";
1246    msg += lfn;
1247    if (is_collection) {
1248       msg += " type: raw_collection;";
1249    // special treatment for collections
1250       is_xml = kFALSE;
1251       // check for tag files in the collection
1252       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1253       if (!res) {
1254          msg += " using_tags: No (unknown)";
1255          Info("CheckDataType", msg.Data());
1256          return;
1257       }   
1258       const char* typeStr = res->GetKey(0, "origLFN");
1259       if (!typeStr || !strlen(typeStr)) {
1260          msg += " using_tags: No (unknown)";
1261          Info("CheckDataType", msg.Data());
1262          return;
1263       }   
1264       TString file = typeStr;
1265       use_tags = file.Contains(".tag");
1266       if (use_tags) msg += " using_tags: Yes";
1267       else          msg += " using_tags: No";
1268       Info("CheckDataType", msg.Data());
1269       return;
1270    }
1271    TString slfn(lfn);
1272    slfn.ToLower();
1273    is_xml = slfn.Contains(".xml");
1274    if (is_xml) {
1275    // Open xml collection and check if there are tag files inside
1276       msg += " type: xml_collection;";
1277       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1278       if (!coll) {
1279          msg += " using_tags: No (unknown)";
1280          Info("CheckDataType", msg.Data());
1281          return;
1282       }   
1283       TMap *map = coll->Next();
1284       if (!map) {
1285          msg += " using_tags: No (unknown)";
1286          Info("CheckDataType", msg.Data());
1287          return;
1288       }   
1289       map = (TMap*)map->GetValue("");
1290       TString file;
1291       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1292       use_tags = file.Contains(".tag");
1293       delete coll;
1294       if (use_tags) msg += " using_tags: Yes";
1295       else          msg += " using_tags: No";
1296       Info("CheckDataType", msg.Data());
1297       return;
1298    }
1299    use_tags = slfn.Contains(".tag");
1300    if (slfn.Contains(".root")) msg += " type: root file;";
1301    else                        msg += " type: unhnown file;";
1302    if (use_tags) msg += " using_tags: Yes";
1303    else          msg += " using_tags: No";
1304    Info("CheckDataType", msg.Data());
1305 }
1306
1307 //______________________________________________________________________________
1308 void AliAnalysisAlien::EnablePackage(const char *package)
1309 {
1310 // Enables a par file supposed to exist in the current directory.
1311    TString pkg(package);
1312    pkg.ReplaceAll(".par", "");
1313    pkg += ".par";
1314    if (gSystem->AccessPathName(pkg)) {
1315       Error("EnablePackage", "Package %s not found", pkg.Data());
1316       return;
1317    }
1318    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1319       Info("EnablePackage", "AliEn plugin will use .par packages");
1320    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1321    if (!fPackages) {
1322       fPackages = new TObjArray();
1323       fPackages->SetOwner();
1324    }
1325    fPackages->Add(new TObjString(pkg));
1326 }      
1327
1328 //______________________________________________________________________________
1329 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1330 {
1331 // Get job status for all jobs with jobid>jobidstart.
1332    static char mstatus[20];
1333    mstatus[0] = '\0';
1334    nrunning = 0;
1335    nwaiting = 0;
1336    nerror   = 0;
1337    ndone    = 0;
1338    TGridJobStatusList *list = gGrid->Ps("");
1339    if (!list) return mstatus;
1340    Int_t nentries = list->GetSize();
1341    TGridJobStatus *status;
1342    Int_t pid;
1343    for (Int_t ijob=0; ijob<nentries; ijob++) {
1344       status = (TGridJobStatus *)list->At(ijob);
1345       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1346       if (pid<jobidstart) continue;
1347       if (pid == lastid) {
1348          gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1349       }   
1350       switch (status->GetStatus()) {
1351          case TGridJobStatus::kWAITING:
1352             nwaiting++; break;
1353          case TGridJobStatus::kRUNNING:
1354             nrunning++; break;
1355          case TGridJobStatus::kABORTED:
1356          case TGridJobStatus::kFAIL:
1357          case TGridJobStatus::kUNKNOWN:
1358             nerror++; break;
1359          case TGridJobStatus::kDONE:
1360             ndone++;
1361       }
1362    }
1363    list->Delete();
1364    delete list;
1365    return mstatus;
1366 }
1367
1368 //______________________________________________________________________________
1369 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1370 {
1371 // Returns true if file is a collection. Functionality duplicated from
1372 // TAlien::Type() because we don't want to directly depend on TAlien.
1373    if (!gGrid) {
1374       Error("IsCollection", "No connection to grid");
1375       return kFALSE;
1376    }
1377    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1378    if (!res) return kFALSE;
1379    const char* typeStr = res->GetKey(0, "type");
1380    if (!typeStr || !strlen(typeStr)) return kFALSE;
1381    if (!strcmp(typeStr, "collection")) return kTRUE;
1382    delete res;
1383    return kFALSE;
1384 }   
1385
1386 //______________________________________________________________________________
1387 Bool_t AliAnalysisAlien::IsSingleOutput() const
1388 {
1389 // Check if single-ouput option is on.
1390    return (!fOutputSingle.IsNull());
1391 }
1392    
1393 //______________________________________________________________________________
1394 void AliAnalysisAlien::Print(Option_t *) const
1395 {
1396 // Print current plugin settings.
1397    printf("### AliEn analysis plugin current settings ###\n");
1398    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1399    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1400    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1401    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1402    if (fUser.Length()) 
1403    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1404    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1405    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1406    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1407    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1408    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1409    if (fRunNumbers.Length()) 
1410    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1411    if (fRunRange[0])
1412    printf("=   Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1413    if (!fRunRange[0] && !fRunNumbers.Length()) {
1414       TIter next(fInputFiles);
1415       TObject *obj;
1416       TString list;
1417       while ((obj=next())) list += obj->GetName();
1418       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1419    }
1420    if (TestBit(AliAnalysisGrid::kTest))
1421    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1422    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1423    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1424    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1425    printf("=====================================================================\n");
1426    printf("=   Job price: ___________________________________ %d\n", fPrice);
1427    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
1428    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1429    if (fMaxInitFailed>0) 
1430    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1431    if (fMasterResubmitThreshold>0) 
1432    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1433    if (fNrunsPerMaster>0)
1434    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1435    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1436    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
1437    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
1438    if (fArguments.Length()) 
1439    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
1440    if (fExecutableArgs.Length()) 
1441    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1442    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1443    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1444    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1445    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1446    if (fDatasetName)
1447    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1448    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1449    if (fIncludePath.Data())
1450    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1451    if (fCloseSE.Length())
1452    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1453    if (fFriendChainName.Length())
1454    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1455    if (fPackages) {
1456       TIter next(fPackages);
1457       TObject *obj;
1458       TString list;
1459       while ((obj=next())) list += obj->GetName();
1460       printf("=   Par files to be used: ________________________ %s\n", list.Data());
1461    }   
1462 }
1463
1464 //______________________________________________________________________________
1465 void AliAnalysisAlien::SetDefaults()
1466 {
1467 // Set default values for everything. What cannot be filled will be left empty.
1468    if (fGridJDL) delete fGridJDL;
1469    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1470    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1471    fPrice                      = 1;
1472    fTTL                        = 30000;
1473    fSplitMaxInputFileNumber    = 100;
1474    fMaxInitFailed              = 0;
1475    fMasterResubmitThreshold    = 0;
1476    fNtestFiles                 = 10;
1477    fRunRange[0]                = 0;
1478    fRunRange[1]                = 0;
1479    fNrunsPerMaster             = 1;
1480    fMaxMergeFiles              = 100;
1481    fRunNumbers                 = "";
1482    fExecutable                 = "analysis.sh";
1483    fExecutableCommand          = "root -b -q";
1484    fArguments                  = "";
1485    fExecutableArgs             = "";
1486    fAnalysisMacro              = "myAnalysis.C";
1487    fAnalysisSource             = "";
1488    fAdditionalLibs             = "";
1489    fSplitMode                  = "se";
1490    fAPIVersion                 = "";
1491    fROOTVersion                = "";
1492    fAliROOTVersion             = "";
1493    fUser                       = "";  // Your alien user name
1494    fGridWorkingDir             = "";
1495    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1496    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1497    fFriendChainName            = "";
1498    fGridOutputDir              = "output";
1499    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1500    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1501    fInputFormat                = "xml-single";
1502    fJDLName                    = "analysis.jdl";
1503    fJobTag                     = "Automatically generated analysis JDL";
1504    fMergeExcludes              = "";
1505    fMergeViaJDL                = 0;
1506 }   
1507
1508 //______________________________________________________________________________
1509 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge)
1510 {
1511 // Merge all registered outputs from basedir.
1512    TString output_file = output;
1513    TString command;
1514    TString output_chunk;
1515    TString previous_chunk = "";
1516    Int_t count_chunk = 0;
1517    Int_t count_zero = nmaxmerge;
1518    Bool_t merged = kTRUE;
1519    Int_t index = output_file.Index("@");
1520    if (index > 0) output_file.Remove(index);
1521    command = Form("find %s/ *%s", basedir, output_file.Data());
1522    printf("command: %s\n", command.Data());
1523    TGridResult *res = gGrid->Command(command);
1524    if (!res) {
1525       printf("Error: No result for the find command\n");
1526       return kFALSE;
1527    }     
1528
1529    TFileMerger *fm = 0;
1530    TIter nextmap(res);
1531    TMap *map = 0;
1532    // Check if there is a merge operation to resume
1533    output_chunk = output_file;
1534    output_chunk.ReplaceAll(".root", "_*.root");
1535    // Check for existent temporary merge files
1536    if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1537       while (1) {
1538          // Skip as many input files as in a chunk
1539          for (Int_t counter=0; counter<nmaxmerge; counter++) map = (TMap*)nextmap();
1540          if (!map) {
1541             ::Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1542             delete res;
1543             return kFALSE;
1544          }
1545          output_chunk = output_file;
1546          output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1547          count_chunk++;
1548          if (gSystem->AccessPathName(output_chunk)) continue;
1549          // Merged file with chunks up to <count_chunk> found
1550          printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1551          previous_chunk = output_chunk;
1552          break;
1553       }
1554    }   
1555    count_zero = nmaxmerge;
1556    
1557    while ((map=(TMap*)nextmap())) {
1558    // Loop 'find' results and get next LFN
1559       if (count_zero == nmaxmerge) {
1560          // First file in chunk - create file merger and add previous chunk if any.
1561          fm = new TFileMerger(kFALSE);
1562          fm->SetFastMethod(kTRUE);
1563          if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1564          output_chunk = output_file;
1565          output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1566       }
1567       // If last file found, put merged results in the output file
1568       if (map == res->Last()) output_chunk = output_file;
1569       TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1570       if (!objs || !objs->GetString().Length()) {
1571          // Nothing found - skip this output
1572          delete res;
1573          delete fm;
1574          return kFALSE;
1575       } 
1576       // Add file to be merged and decrement chunk counter.
1577       fm->AddFile(objs->GetString());
1578       count_zero--;
1579       if (count_zero==0 || map == res->Last()) {            
1580          fm->OutputFile(output_chunk);
1581          if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1582          // Nothing found - skip this output
1583             ::Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1584             delete res;
1585             delete fm;
1586             return kFALSE;
1587          }
1588          // Merge the outputs, then go to next chunk      
1589          if (!fm->Merge()) {
1590             ::Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1591             delete res;
1592             delete fm;
1593             merged = kFALSE;
1594             return kFALSE;
1595          } else {
1596             ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1597             gSystem->Unlink(previous_chunk);
1598          }
1599          if (map == res->Last()) {
1600             delete res;
1601             delete fm;
1602             break;
1603          }      
1604          count_chunk++;
1605          count_zero = nmaxmerge;
1606          previous_chunk = output_chunk;
1607       }
1608    }
1609    return merged;
1610
1611
1612 //______________________________________________________________________________
1613 Bool_t AliAnalysisAlien::MergeOutputs()
1614 {
1615 // Merge analysis outputs existing in the AliEn space.
1616    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1617    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1618    if (!Connect()) {
1619       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1620       return kFALSE;
1621    }
1622    if (fMergeViaJDL && !fProductionMode && TestBit(AliAnalysisGrid::kMerge)) {
1623       Info("MergeOutputs", "Submitting merging JDL");
1624       SubmitMerging();
1625       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
1626       Info("MergeOutputs", "### Trying to continue merging ... (may fail if exited the shell prematurely)");
1627    }   
1628    // Get the output path
1629    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1630    if (!DirectoryExists(fGridOutputDir)) {
1631       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1632       return kFALSE;
1633    }
1634    if (!fOutputFiles.Length()) {
1635       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1636       return kFALSE;
1637    }
1638    // Check if fast read option was requested
1639    if (fFastReadOption) {
1640       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !");
1641       gEnv->SetValue("XNet.ConnectTimeout",5);
1642       gEnv->SetValue("XNet.RequestTimeout",5);
1643       gEnv->SetValue("XNet.MaxRedirectCount",2);
1644       gEnv->SetValue("XNet.ReconnectTimeout",5);
1645       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
1646    }   
1647    TObjArray *list = fOutputFiles.Tokenize(" ");
1648    TIter next(list);
1649    TObjString *str;
1650    TString output_file;
1651    Bool_t merged = kTRUE;
1652    while((str=(TObjString*)next())) {
1653       output_file = str->GetString();
1654       Int_t index = output_file.Index("@");
1655       if (index > 0) output_file.Remove(index);
1656       // Skip already merged outputs
1657       if (!gSystem->AccessPathName(output_file)) {
1658          Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1659          continue;
1660       }   
1661       if (fMergeExcludes.Length() &&
1662           fMergeExcludes.Contains(output_file.Data())) continue;
1663       // Perform a 'find' command in the output directory, looking for registered outputs    
1664       merged = MergeOutput(output_file, fGridOutputDir, fMaxMergeFiles);
1665       if (!merged) {
1666          Error("MergeOutputs", "Terminate() will  NOT be executed");
1667          return kFALSE;
1668       }   
1669    } 
1670    return kTRUE;
1671 }   
1672
1673 //______________________________________________________________________________
1674 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1675 {
1676 // Use the output files connected to output containers from the analysis manager
1677 // rather than the files defined by SetOutputFiles
1678    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1679       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1680       analysis manager");
1681    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1682 }
1683       
1684 //______________________________________________________________________________
1685 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1686 {
1687 // Start remote grid analysis.
1688    
1689    // Check if output files have to be taken from the analysis manager
1690    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1691       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1692       if (!mgr || !mgr->IsInitialized()) {
1693          Error("StartAnalysis", "You need an initialized analysis manager for this");
1694          return kFALSE;
1695       }
1696       fOutputFiles = "";
1697       TIter next(mgr->GetOutputs());
1698       AliAnalysisDataContainer *output;
1699       while ((output=(AliAnalysisDataContainer*)next())) {
1700          const char *filename = output->GetFileName();
1701          if (!(strcmp(filename, "default"))) {
1702             if (!mgr->GetOutputEventHandler()) continue;
1703             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1704          }
1705          if (fOutputFiles.Contains(filename)) continue;
1706          if (fOutputFiles.Length()) fOutputFiles += " ";
1707          fOutputFiles += filename;
1708       }
1709       // Add extra files registered to the analysis manager
1710       if (mgr->GetExtraFiles().Length()) {
1711          if (fOutputFiles.Length()) fOutputFiles += " ";
1712          fOutputFiles += mgr->GetExtraFiles();
1713       }
1714    }
1715 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1716    if (TestBit(AliAnalysisGrid::kOffline)) {
1717       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1718       \n                         there nor any job run. You can revise the JDL and analysis \
1719       \n                         macro then run the same in \"submit\" mode.");
1720    } else if (TestBit(AliAnalysisGrid::kTest)) {
1721       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1722       \n                         dataset.");
1723    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1724       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1725       \n                         space and job submitted.");
1726    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1727       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1728       if (fMergeViaJDL) CheckInputData();
1729       return kTRUE;
1730    } else {
1731       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1732    }   
1733       
1734    if (!Connect()) {
1735       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1736       return kFALSE;
1737    }
1738    Print();   
1739    if (!CheckInputData()) {
1740       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1741       return kFALSE;
1742    }   
1743    CreateDataset(fDataPattern);
1744    WriteAnalysisFile();   
1745    WriteAnalysisMacro();
1746    WriteExecutable();
1747    WriteValidationScript();
1748    if (fMergeViaJDL) {
1749       WriteMergingMacro();
1750       WriteMergeExecutable();
1751       WriteValidationScript(kTRUE);
1752    }   
1753    if (!CreateJDL()) return kFALSE;
1754    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1755    if (TestBit(AliAnalysisGrid::kTest)) {
1756       // Locally testing the analysis
1757       Info("StartAnalysis", "\n_______________________________________________________________________ \
1758       \n   Running analysis script in a daughter shell as on a worker node \
1759       \n_______________________________________________________________________");
1760       TObjArray *list = fOutputFiles.Tokenize(" ");
1761       TIter next(list);
1762       TObjString *str;
1763       TString output_file;
1764       while((str=(TObjString*)next())) {
1765          output_file = str->GetString();
1766          Int_t index = output_file.Index("@");
1767          if (index > 0) output_file.Remove(index);         
1768          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1769       }
1770       delete list;
1771       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1772       TString validationScript = fExecutable;
1773       validationScript.ReplaceAll(".sh", "_validation.sh");
1774       gSystem->Exec(Form("bash %s",validationScript.Data()));
1775 //      gSystem->Exec("cat stdout");
1776       return kFALSE;
1777    }
1778    // Check if submitting is managed by LPM manager
1779    if (fProductionMode) {
1780       TString prodfile = fJDLName;
1781       prodfile.ReplaceAll(".jdl", ".prod");
1782       WriteProductionFile(prodfile);
1783       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1784       return kFALSE;
1785    }   
1786    // Submit AliEn job(s)
1787    gGrid->Cd(fGridOutputDir);
1788    TGridResult *res;
1789    TString jobID = "";
1790    if (!fRunNumbers.Length() && !fRunRange[0]) {
1791       // Submit a given xml or a set of runs
1792       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1793       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1794       if (res) {
1795          const char *cjobId = res->GetKey(0,"jobId");
1796          if (!cjobId) {
1797             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1798             return kFALSE;
1799          } else {
1800             Info("StartAnalysis", "\n_______________________________________________________________________ \
1801             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1802             \n_______________________________________________________________________",
1803                    fJDLName.Data(), cjobId);
1804             jobID = cjobId;      
1805          }          
1806          delete res;
1807       }   
1808    } else {
1809       // Submit for a range of enumeration of runs.
1810       Submit();
1811    }   
1812          
1813    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1814    \n You may exit at any time and terminate the job later using the option <terminate> \
1815    \n ##################################################################################", jobID.Data());
1816    gSystem->Exec("aliensh");
1817    return kTRUE;
1818 }
1819
1820 //______________________________________________________________________________
1821 void AliAnalysisAlien::Submit()
1822 {
1823 // Submit all master jobs.
1824    Int_t nmasterjobs = fInputFiles->GetEntries();
1825    Long_t tshoot = gSystem->Now();
1826    if (!fNsubmitted) SubmitNext();
1827    while (fNsubmitted < nmasterjobs) {
1828       Long_t now = gSystem->Now();
1829       if ((now-tshoot)>30000) {
1830          tshoot = now;
1831          SubmitNext();
1832       }   
1833    }
1834 }
1835
1836 //______________________________________________________________________________
1837 void AliAnalysisAlien::SubmitMerging()
1838 {
1839 // Submit all merging jobs.
1840    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1841    gGrid->Cd(fGridOutputDir);
1842    TString mergeJDLName = fExecutable;
1843    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1844    Int_t ntosubmit = fInputFiles->GetEntries();
1845    printf("### Submitting %d merging jobs...\n", ntosubmit);
1846    for (Int_t i=0; i<ntosubmit; i++) {
1847       TString query;
1848       query = Form("submit %s %03d", mergeJDLName.Data(), i);
1849       printf("********* %s\n",query.Data());
1850       TGridResult *res = gGrid->Command(query);
1851       if (res) {
1852          const char *cjobId = res->GetKey(0,"jobId");
1853          if (!cjobId) {
1854             Error("StartAnalysis", "Your JDL %s could not be submitted", mergeJDLName.Data());
1855             return;
1856          } else {
1857             Info("StartAnalysis", "\n_______________________________________________________________________ \
1858             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1859             \n_______________________________________________________________________",
1860                    mergeJDLName.Data(), cjobId);
1861          }
1862          delete res;
1863       }             
1864    }
1865    if (!ntosubmit) return;
1866    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
1867    \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
1868    \n ##################################################################################");
1869    gSystem->Exec("aliensh");
1870 }
1871
1872 //______________________________________________________________________________
1873 void AliAnalysisAlien::SubmitNext()
1874 {
1875 // Submit next bunch of master jobs if the queue is free.
1876    static Bool_t iscalled = kFALSE;
1877    static Int_t firstmaster = 0;
1878    static Int_t lastmaster = 0;
1879    static Int_t npermaster  = 0;
1880    if (iscalled) return;
1881    iscalled = kTRUE;
1882    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1883    Int_t ntosubmit = 0;
1884    TGridResult *res;
1885    TString jobID = "";
1886    if (!fNsubmitted) ntosubmit = 1;
1887    else {
1888       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1889       printf("=== master %d: %s\n", lastmaster, status.Data());
1890       // If last master not split, just return
1891       if (status != "SPLIT") {iscalled = kFALSE; return;}
1892       // No more than 100 waiting jobs
1893       if (nwaiting>100) {iscalled = kFALSE; return;}
1894       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
1895       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1896       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
1897              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1898    }
1899    Int_t nmasterjobs = fInputFiles->GetEntries();
1900    for (Int_t i=0; i<ntosubmit; i++) {
1901       // Submit for a range of enumeration of runs.
1902       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1903       TString query;
1904       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
1905       runOutDir.ReplaceAll(".xml", "");
1906       if (fOutputToRunNo)
1907          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
1908       else
1909          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1910       printf("********* %s\n",query.Data());
1911       res = gGrid->Command(query);
1912       if (res) {
1913          TString cjobId1 = res->GetKey(0,"jobId");
1914          if (!cjobId1.Length()) {
1915             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1916             iscalled = kFALSE;
1917             return;
1918          } else {
1919             Info("StartAnalysis", "\n_______________________________________________________________________ \
1920             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1921             \n_______________________________________________________________________",
1922                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1923             jobID += cjobId1;
1924             jobID += " ";
1925             lastmaster = cjobId1.Atoi();
1926             if (!firstmaster) firstmaster = lastmaster;
1927             fNsubmitted++;
1928          }          
1929          delete res;
1930       }   
1931    }
1932    iscalled = kFALSE;
1933 }
1934
1935 //______________________________________________________________________________
1936 void AliAnalysisAlien::WriteAnalysisFile()
1937 {
1938 // Write current analysis manager into the file <analysisFile>
1939    TString analysisFile = fExecutable;
1940    analysisFile.ReplaceAll(".sh", ".root");
1941    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1942       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1943       if (!mgr || !mgr->IsInitialized()) {
1944          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1945          return;
1946       }
1947       // Check analysis type
1948       TObject *handler;
1949       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1950       handler = (TObject*)mgr->GetInputEventHandler();
1951       if (handler) {
1952          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1953          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1954       }
1955       TDirectory *cdir = gDirectory;
1956       TFile *file = TFile::Open(analysisFile, "RECREATE");
1957       if (file) {
1958          // Skip task Terminate calls for the grid job
1959          mgr->SetSkipTerminate(kTRUE);
1960          // Unless merging makes no sense
1961          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
1962          mgr->Write();
1963          delete file;
1964          // Enable termination for local jobs
1965          mgr->SetSkipTerminate(kFALSE);
1966       }
1967       if (cdir) cdir->cd();
1968       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1969    }   
1970    Bool_t copy = kTRUE;
1971    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1972    if (copy) {
1973       CdWork();
1974       TString workdir = gGrid->GetHomeDirectory();
1975       workdir += fGridWorkingDir;
1976       Info("CreateJDL", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1977       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1978       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1979    }   
1980 }
1981
1982 //______________________________________________________________________________
1983 void AliAnalysisAlien::WriteAnalysisMacro()
1984 {
1985 // Write the analysis macro that will steer the analysis in grid mode.
1986    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1987       ofstream out;
1988       out.open(fAnalysisMacro.Data(), ios::out);
1989       if (!out.good()) {
1990          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1991          return;
1992       }
1993       Bool_t hasSTEERBase = kFALSE;
1994       Bool_t hasESD = kFALSE;
1995       Bool_t hasAOD = kFALSE;
1996       Bool_t hasANALYSIS = kFALSE;
1997       Bool_t hasANALYSISalice = kFALSE;
1998       Bool_t hasCORRFW = kFALSE;
1999       TString func = fAnalysisMacro;
2000       TString type = "ESD";
2001       TString comment = "// Analysis using ";
2002       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2003       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2004          type = "AOD";
2005          comment += "AOD";
2006       }   
2007       if (type!="AOD" && fFriendChainName!="") {
2008          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2009          return;
2010       }
2011       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2012       else comment += " data";
2013       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2014       func.ReplaceAll(".C", "");
2015       out << "void " << func.Data() << "()" << endl; 
2016       out << "{" << endl;
2017       out << comment.Data() << endl;
2018       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2019       out << "   TStopwatch timer;" << endl;
2020       out << "   timer.Start();" << endl << endl;
2021       out << "// load base root libraries" << endl;
2022       out << "   gSystem->Load(\"libTree\");" << endl;
2023       out << "   gSystem->Load(\"libGeom\");" << endl;
2024       out << "   gSystem->Load(\"libVMC\");" << endl;
2025       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2026       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2027       if (fAdditionalRootLibs.Length()) {
2028          // in principle libtree /lib geom libvmc etc. can go into this list, too
2029          out << "// Add aditional libraries" << endl;
2030          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2031          TIter next(list);
2032          TObjString *str;
2033          while((str=(TObjString*)next())) {
2034             if (str->GetString().Contains(".so"))
2035             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2036          }
2037          if (list) delete list;
2038       }
2039       out << "// include path" << endl;
2040       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2041       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2042       out << "// Load analysis framework libraries" << endl;
2043       if (!fPackages) {
2044          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2045          out << "   gSystem->Load(\"libESD\");" << endl;
2046          out << "   gSystem->Load(\"libAOD\");" << endl;
2047          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2048          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2049          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2050       } else {
2051          TIter next(fPackages);
2052          TObject *obj;
2053          TString pkgname;
2054          TString setupPar = "AliAnalysisAlien::SetupPar";
2055          while ((obj=next())) {
2056             pkgname = obj->GetName();
2057             if (pkgname == "STEERBase" ||
2058                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2059             if (pkgname == "ESD" ||
2060                 pkgname == "ESD.par")       hasESD = kTRUE;
2061             if (pkgname == "AOD" ||
2062                 pkgname == "AOD.par")       hasAOD = kTRUE;
2063             if (pkgname == "ANALYSIS" ||
2064                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2065             if (pkgname == "ANALYSISalice" ||
2066                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2067             if (pkgname == "CORRFW" ||
2068                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2069          }
2070          if (hasANALYSISalice) setupPar = "SetupPar";   
2071          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2072          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2073          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2074          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2075          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2076          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2077          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2078          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2079          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2080          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2081          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2082          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2083          out << "// Compile other par packages" << endl;
2084          next.Reset();
2085          while ((obj=next())) {
2086             pkgname = obj->GetName();
2087             if (pkgname == "STEERBase" ||
2088                 pkgname == "STEERBase.par" ||
2089                 pkgname == "ESD" ||
2090                 pkgname == "ESD.par" ||
2091                 pkgname == "AOD" ||
2092                 pkgname == "AOD.par" ||
2093                 pkgname == "ANALYSIS" ||
2094                 pkgname == "ANALYSIS.par" ||
2095                 pkgname == "ANALYSISalice" ||
2096                 pkgname == "ANALYSISalice.par" ||
2097                 pkgname == "CORRFW" ||
2098                 pkgname == "CORRFW.par") continue;
2099             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2100          }   
2101       }   
2102       if (fAdditionalLibs.Length()) {
2103          out << "// Add aditional AliRoot libraries" << endl;
2104          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2105          TIter next(list);
2106          TObjString *str;
2107          while((str=(TObjString*)next())) {
2108             if (str->GetString().Contains(".so"))
2109                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2110          }
2111          if (list) delete list;
2112       }
2113       out << endl;
2114       out << "// analysis source to be compiled at runtime (if any)" << endl;
2115       if (fAnalysisSource.Length()) {
2116          TObjArray *list = fAnalysisSource.Tokenize(" ");
2117          TIter next(list);
2118          TObjString *str;
2119          while((str=(TObjString*)next())) {
2120             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2121          }   
2122          if (list) delete list;
2123       }
2124       out << endl;
2125       if (fFastReadOption) {
2126          Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. Note that this may skip some files that could be accessed !!!");
2127          out << "// fast xrootd reading enabled" << endl;
2128          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2129          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",5);" << endl;
2130          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",5);" << endl;
2131          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2132          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",5);" << endl;
2133          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2134       }   
2135       out << "// connect to AliEn and make the chain" << endl;
2136       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2137       if (IsUsingTags()) {
2138          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2139       } else {
2140          if(fFriendChainName!="AliAOD.VertexingHF.root") {
2141             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
2142          } else {
2143             out << "   // Check if the macro to create the chain was provided" << endl;
2144             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
2145             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
2146             out << "      return;" << endl;
2147             out << "   }" << endl;
2148             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
2149             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
2150          }  
2151       }   
2152       out << "// read the analysis manager from file" << endl;
2153       TString analysisFile = fExecutable;
2154       analysisFile.ReplaceAll(".sh", ".root");
2155       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2156       out << "   if (!file) return;" << endl; 
2157       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
2158       out << "   AliAnalysisManager *mgr = 0;" << endl;
2159       out << "   TKey *key;" << endl;
2160       out << "   while ((key=(TKey*)nextkey())) {" << endl;
2161       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2162       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2163       out << "   };" << endl;
2164       out << "   if (!mgr) {" << endl;
2165       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2166       out << "      return;" << endl;
2167       out << "   }" << endl << endl;
2168       out << "   mgr->PrintStatus();" << endl;
2169       if (AliAnalysisManager::GetAnalysisManager()) {
2170          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>2) {
2171             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2172          } else {
2173             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2174          }
2175       }   
2176       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
2177       out << "   timer.Stop();" << endl;
2178       out << "   timer.Print();" << endl;
2179       out << "}" << endl << endl;
2180       if (IsUsingTags()) {
2181          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2182          out << "{" << endl;
2183          out << "// Create a chain using tags from the xml file." << endl;
2184          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2185          out << "   if (!coll) {" << endl;
2186          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2187          out << "      return NULL;" << endl;
2188          out << "   }" << endl;
2189          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2190          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2191          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
2192          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
2193          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
2194          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2195          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
2196          out << "   // Check if the cuts configuration file was provided" << endl;
2197          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2198          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2199          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2200          out << "   }" << endl;
2201          if (fFriendChainName=="") {
2202             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2203          } else {
2204             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
2205             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2206             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2207          }
2208          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2209          out << "   chain->ls();" << endl;
2210          out << "   return chain;" << endl;
2211          out << "}" << endl << endl;
2212          if (gSystem->AccessPathName("ConfigureCuts.C")) {
2213             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
2214             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2215             msg += "                      AliLHCTagCuts *lhcCuts,\n";
2216             msg += "                      AliDetectorTagCuts *detCuts,\n";
2217             msg += "                      AliEventTagCuts *evCuts)";
2218             Info("WriteAnalysisMacro", msg.Data());
2219          }
2220       } 
2221       if (!IsUsingTags() || fFriendChainName!="") {
2222          out <<"//________________________________________________________________________________" << endl;
2223          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2224          out << "{" << endl;
2225          out << "// Create a chain using url's from xml file" << endl;
2226          out << "   TString treename = type;" << endl;
2227          out << "   treename.ToLower();" << endl;
2228          out << "   treename += \"Tree\";" << endl;
2229          out << "   printf(\"***************************************\\n\");" << endl;
2230          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
2231          out << "   printf(\"***************************************\\n\");" << endl;
2232          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2233          out << "   if (!coll) {" << endl;
2234          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2235          out << "      return NULL;" << endl;
2236          out << "   }" << endl;
2237          out << "   TChain *chain = new TChain(treename);" << endl;
2238          if(fFriendChainName!="") {
2239             out << "   TChain *chainFriend = new TChain(treename);" << endl;
2240          }
2241          out << "   coll->Reset();" << endl;
2242          out << "   while (coll->Next()) {" << endl;
2243          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
2244          if(fFriendChainName!="") {
2245             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
2246             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2247             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2248             out << "      chainFriend->Add(fileFriend.Data());" << endl;
2249          }
2250          out << "   }" << endl;
2251          out << "   if (!chain->GetNtrees()) {" << endl;
2252          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2253          out << "      return NULL;" << endl;
2254          out << "   }" << endl;
2255          if(fFriendChainName!="") {
2256             out << "   chain->AddFriend(chainFriend);" << endl;
2257          }
2258          out << "   return chain;" << endl;
2259          out << "}" << endl << endl;
2260       }   
2261       if (hasANALYSISalice) {
2262          out <<"//________________________________________________________________________________" << endl;
2263          out << "Bool_t SetupPar(const char *package) {" << endl;
2264          out << "// Compile the package and set it up." << endl;
2265          out << "   TString pkgdir = package;" << endl;
2266          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2267          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2268          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2269          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2270          out << "   // Check for BUILD.sh and execute" << endl;
2271          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2272          out << "      printf(\"*******************************\\n\");" << endl;
2273          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2274          out << "      printf(\"*******************************\\n\");" << endl;
2275          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2276          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2277          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2278          out << "         return kFALSE;" << endl;
2279          out << "      }" << endl;
2280          out << "   } else {" << endl;
2281          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2282          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2283          out << "      return kFALSE;" << endl;
2284          out << "   }" << endl;
2285          out << "   // Check for SETUP.C and execute" << endl;
2286          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2287          out << "      printf(\"*******************************\\n\");" << endl;
2288          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2289          out << "      printf(\"*******************************\\n\");" << endl;
2290          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2291          out << "   } else {" << endl;
2292          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2293          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2294          out << "      return kFALSE;" << endl;
2295          out << "   }" << endl;
2296          out << "   // Restore original workdir" << endl;
2297          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2298          out << "   return kTRUE;" << endl;
2299          out << "}" << endl;
2300       }
2301       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2302    }   
2303    Bool_t copy = kTRUE;
2304    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2305    if (copy) {
2306       CdWork();
2307       TString workdir = gGrid->GetHomeDirectory();
2308       workdir += fGridWorkingDir;
2309       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2310       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2311          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2312          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2313          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2314       }   
2315       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2316       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2317    }
2318 }
2319
2320 //______________________________________________________________________________
2321 void AliAnalysisAlien::WriteMergingMacro()
2322 {
2323 // Write a macro to merge the outputs per master job.
2324    if (!fMergeViaJDL) return;
2325    if (!fOutputFiles.Length()) {
2326       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2327       return;
2328    }   
2329    TString mergingMacro = fExecutable;
2330    mergingMacro.ReplaceAll(".sh","_merge.C");
2331    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2332    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2333       ofstream out;
2334       out.open(mergingMacro.Data(), ios::out);
2335       if (!out.good()) {
2336          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2337          return;
2338       }
2339       Bool_t hasSTEERBase = kFALSE;
2340       Bool_t hasESD = kFALSE;
2341       Bool_t hasAOD = kFALSE;
2342       Bool_t hasANALYSIS = kFALSE;
2343       Bool_t hasANALYSISalice = kFALSE;
2344       Bool_t hasCORRFW = kFALSE;
2345       TString func = mergingMacro;
2346       TString comment;
2347       func.ReplaceAll(".C", "");
2348       out << "void " << func.Data() << "(const char *dir)" << endl;
2349       out << "{" << endl;
2350       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
2351       out << "   TStopwatch timer;" << endl;
2352       out << "   timer.Start();" << endl << endl;
2353       out << "// load base root libraries" << endl;
2354       out << "   gSystem->Load(\"libTree\");" << endl;
2355       out << "   gSystem->Load(\"libGeom\");" << endl;
2356       out << "   gSystem->Load(\"libVMC\");" << endl;
2357       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2358       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2359       if (fAdditionalRootLibs.Length()) {
2360          // in principle libtree /lib geom libvmc etc. can go into this list, too
2361          out << "// Add aditional libraries" << endl;
2362          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2363          TIter next(list);
2364          TObjString *str;
2365          while((str=(TObjString*)next())) {
2366             if (str->GetString().Contains(".so"))
2367             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2368          }
2369          if (list) delete list;
2370       }
2371       out << "// include path" << endl;
2372       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2373       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2374       out << "// Load analysis framework libraries" << endl;
2375       if (!fPackages) {
2376          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2377          out << "   gSystem->Load(\"libESD\");" << endl;
2378          out << "   gSystem->Load(\"libAOD\");" << endl;
2379          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2380          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2381          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2382       } else {
2383          TIter next(fPackages);
2384          TObject *obj;
2385          TString pkgname;
2386          TString setupPar = "AliAnalysisAlien::SetupPar";
2387          while ((obj=next())) {
2388             pkgname = obj->GetName();
2389             if (pkgname == "STEERBase" ||
2390                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2391             if (pkgname == "ESD" ||
2392                 pkgname == "ESD.par")       hasESD = kTRUE;
2393             if (pkgname == "AOD" ||
2394                 pkgname == "AOD.par")       hasAOD = kTRUE;
2395             if (pkgname == "ANALYSIS" ||
2396                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2397             if (pkgname == "ANALYSISalice" ||
2398                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2399             if (pkgname == "CORRFW" ||
2400                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2401          }   
2402          if (hasANALYSISalice) setupPar = "SetupPar";   
2403          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2404          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2405          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2406          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2407          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2408          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2409          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2410          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2411          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2412          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2413          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2414          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2415          out << "// Compile other par packages" << endl;
2416          next.Reset();
2417          while ((obj=next())) {
2418             pkgname = obj->GetName();
2419             if (pkgname == "STEERBase" ||
2420                 pkgname == "STEERBase.par" ||
2421                 pkgname == "ESD" ||
2422                 pkgname == "ESD.par" ||
2423                 pkgname == "AOD" ||
2424                 pkgname == "AOD.par" ||
2425                 pkgname == "ANALYSIS" ||
2426                 pkgname == "ANALYSIS.par" ||
2427                 pkgname == "ANALYSISalice" ||
2428                 pkgname == "ANALYSISalice.par" ||
2429                 pkgname == "CORRFW" ||
2430                 pkgname == "CORRFW.par") continue;
2431             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2432          }   
2433       }   
2434       if (fAdditionalLibs.Length()) {
2435          out << "// Add aditional AliRoot libraries" << endl;
2436          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2437          TIter next(list);
2438          TObjString *str;
2439          while((str=(TObjString*)next())) {
2440             if (str->GetString().Contains(".so"))
2441                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2442          }
2443          if (list) delete list;
2444       }
2445       out << endl;
2446       out << "// Analysis source to be compiled at runtime (if any)" << endl;
2447       if (fAnalysisSource.Length()) {
2448          TObjArray *list = fAnalysisSource.Tokenize(" ");
2449          TIter next(list);
2450          TObjString *str;
2451          while((str=(TObjString*)next())) {
2452             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2453          }   
2454          if (list) delete list;
2455       }
2456       out << endl;
2457       if (fFastReadOption) {
2458          Warning("WriteMergingMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid merging jobs. Note that this may skip some files that could be accessed !!!");
2459          out << "// fast xrootd reading enabled" << endl;
2460          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2461          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",5);" << endl;
2462          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",5);" << endl;
2463          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2464          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",5);" << endl;
2465          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2466       }   
2467       out << "// Connect to AliEn" << endl;
2468       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2469       out << "   TString outputDir = \"" << fGridOutputDir << "/\";" << endl;  
2470       out << "   outputDir += dir;" << endl;    
2471       out << "   TString outputFiles = \"" << fOutputFiles << "\";" << endl;
2472       out << "   TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
2473       out << "   TObjArray *list = outputFiles.Tokenize(\" \");" << endl;
2474       out << "   TIter *iter = new TIter(list);" << endl;
2475       out << "   TObjString *str;" << endl;
2476       out << "   TString output_file;" << endl;
2477       out << "   Bool_t merged = kTRUE;" << endl;
2478       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
2479       out << "      output_file = str->GetString();" << endl;
2480       out << "      Int_t index = output_file.Index(\"@\");" << endl;
2481       out << "      if (index > 0) output_file.Remove(index);" << endl;
2482       out << "      // Skip already merged outputs" << endl;
2483       out << "      if (!gSystem->AccessPathName(output_file)) {" << endl;
2484       out << "         printf(\"Output file <%s> found. Not merging again.\",output_file.Data());" << endl;
2485       out << "         continue;" << endl;
2486       out << "      }" << endl;
2487       out << "      if (mergeExcludes.Contains(output_file.Data())) continue;" << endl;
2488       out << "      merged = AliAnalysisAlien::MergeOutput(output_file, outputDir, " << fMaxMergeFiles << ");" << endl;
2489       out << "      if (!merged) {" << endl;
2490       out << "         printf(\"ERROR: Cannot merge %s\\n\", output_file.Data());" << endl;
2491       out << "         return;" << endl;
2492       out << "      }" << endl;
2493       out << "   }" << endl;
2494       out << "}" << endl << endl;
2495       if (hasANALYSISalice) {
2496          out <<"//________________________________________________________________________________" << endl;
2497          out << "Bool_t SetupPar(const char *package) {" << endl;
2498          out << "// Compile the package and set it up." << endl;
2499          out << "   TString pkgdir = package;" << endl;
2500          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2501          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2502          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2503          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2504          out << "   // Check for BUILD.sh and execute" << endl;
2505          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2506          out << "      printf(\"*******************************\\n\");" << endl;
2507          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2508          out << "      printf(\"*******************************\\n\");" << endl;
2509          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2510          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2511          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2512          out << "         return kFALSE;" << endl;
2513          out << "      }" << endl;
2514          out << "   } else {" << endl;
2515          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2516          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2517          out << "      return kFALSE;" << endl;
2518          out << "   }" << endl;
2519          out << "   // Check for SETUP.C and execute" << endl;
2520          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2521          out << "      printf(\"*******************************\\n\");" << endl;
2522          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2523          out << "      printf(\"*******************************\\n\");" << endl;
2524          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2525          out << "   } else {" << endl;
2526          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2527          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2528          out << "      return kFALSE;" << endl;
2529          out << "   }" << endl;
2530          out << "   // Restore original workdir" << endl;
2531          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2532          out << "   return kTRUE;" << endl;
2533          out << "}" << endl;
2534       }
2535    }   
2536    Bool_t copy = kTRUE;
2537    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2538    if (copy) {
2539       CdWork();
2540       TString workdir = gGrid->GetHomeDirectory();
2541       workdir += fGridWorkingDir;
2542       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
2543       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
2544       TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
2545    }
2546 }
2547
2548 //______________________________________________________________________________
2549 Bool_t AliAnalysisAlien::SetupPar(const char *package)
2550 {
2551 // Compile the par file archive pointed by <package>. This must be present in the current durectory.
2552 // Note that for loading the compiled library. The current directory should have precedence in
2553 // LD_LIBRARY_PATH
2554    TString pkgdir = package;
2555    pkgdir.ReplaceAll(".par","");
2556    gSystem->Exec(Form("tar xvzf %s.par", pkgdir.Data()));
2557    TString cdir = gSystem->WorkingDirectory();
2558    gSystem->ChangeDirectory(pkgdir);
2559    // Check for BUILD.sh and execute
2560    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
2561       printf("**************************************************\n");
2562       printf("*** Building PAR archive %s\n", package);
2563       printf("**************************************************\n");
2564       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
2565          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
2566          gSystem->ChangeDirectory(cdir);
2567          return kFALSE;
2568       }
2569    } else {
2570       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
2571       gSystem->ChangeDirectory(cdir);
2572       return kFALSE;
2573    }
2574    // Check for SETUP.C and execute
2575    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
2576       printf("**************************************************\n");
2577       printf("*** Setup PAR archive %s\n", package);
2578       printf("**************************************************\n");
2579       gROOT->Macro("PROOF-INF/SETUP.C");
2580       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
2581    } else {
2582       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
2583       gSystem->ChangeDirectory(cdir);
2584       return kFALSE;
2585    }   
2586    // Restore original workdir
2587    gSystem->ChangeDirectory(cdir);
2588    return kTRUE;
2589 }
2590
2591 //______________________________________________________________________________
2592 void AliAnalysisAlien::WriteExecutable()
2593 {
2594 // Generate the alien executable script.
2595    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2596       ofstream out;
2597       out.open(fExecutable.Data(), ios::out);
2598       if (out.bad()) {
2599          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2600          return;
2601       }
2602       out << "#!/bin/bash" << endl;
2603       out << "echo \"=========================================\"" << endl; 
2604       out << "echo \"############## PATH : ##############\"" << endl;
2605       out << "echo $PATH" << endl;
2606       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2607       out << "echo $LD_LIBRARY_PATH" << endl;
2608       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2609       out << "echo $ROOTSYS" << endl;
2610       out << "echo \"############## which root : ##############\"" << endl;
2611       out << "which root" << endl;
2612       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2613       out << "echo $ALICE_ROOT" << endl;
2614       out << "echo \"############## which aliroot : ##############\"" << endl;
2615       out << "which aliroot" << endl;
2616       out << "echo \"############## system limits : ##############\"" << endl;
2617       out << "ulimit -a" << endl;
2618       out << "echo \"############## memory : ##############\"" << endl;
2619       out << "free -m" << endl;
2620       out << "echo \"=========================================\"" << endl << endl;
2621       // Make sure we can properly compile par files
2622       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2623       out << fExecutableCommand << " "; 
2624       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2625       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2626       out << "echo \"############## memory after: ##############\"" << endl;
2627       out << "free -m" << endl;
2628       out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2629       out << "dmesg | tail -n 10" << endl;
2630    }   
2631    Bool_t copy = kTRUE;
2632    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2633    if (copy) {
2634       CdWork();
2635       TString workdir = gGrid->GetHomeDirectory();
2636       TString bindir = Form("%s/bin", workdir.Data());
2637       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2638       workdir += fGridWorkingDir;
2639       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2640       if (FileExists(executable)) gGrid->Rm(executable);
2641       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2642       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2643    } 
2644 }
2645
2646 //______________________________________________________________________________
2647 void AliAnalysisAlien::WriteMergeExecutable()
2648 {
2649 // Generate the alien executable script for the merging job.
2650    if (!fMergeViaJDL) return;
2651    TString mergeExec = fExecutable;
2652    mergeExec.ReplaceAll(".sh", "_merge.sh");
2653    if (!TestBit(AliAnalysisGrid::kSubmit)) {
2654       ofstream out;
2655       out.open(mergeExec.Data(), ios::out);
2656       if (out.bad()) {
2657          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
2658          return;
2659       }
2660       out << "#!/bin/bash" << endl;
2661       out << "echo \"=========================================\"" << endl; 
2662       out << "echo \"############## PATH : ##############\"" << endl;
2663       out << "echo $PATH" << endl;
2664       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2665       out << "echo $LD_LIBRARY_PATH" << endl;
2666       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2667       out << "echo $ROOTSYS" << endl;
2668       out << "echo \"############## which root : ##############\"" << endl;
2669       out << "which root" << endl;
2670       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2671       out << "echo $ALICE_ROOT" << endl;
2672       out << "echo \"############## which aliroot : ##############\"" << endl;
2673       out << "which aliroot" << endl;
2674       out << "echo \"############## system limits : ##############\"" << endl;
2675       out << "ulimit -a" << endl;
2676       out << "echo \"############## memory : ##############\"" << endl;
2677       out << "free -m" << endl;
2678       out << "echo \"=========================================\"" << endl << endl;
2679       // Make sure we can properly compile par files
2680       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2681       TString mergeMacro = fExecutable;
2682       mergeMacro.ReplaceAll(".sh", "_merge.C");
2683       out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
2684       out << fExecutableCommand << " " << "$ARG" << endl; 
2685       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
2686       out << "echo \"############## memory after: ##############\"" << endl;
2687       out << "free -m" << endl;
2688       out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2689       out << "dmesg | tail -n 10" << endl;
2690    }   
2691    Bool_t copy = kTRUE;
2692    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2693    if (copy) {
2694       CdWork();
2695       TString workdir = gGrid->GetHomeDirectory();
2696       TString bindir = Form("%s/bin", workdir.Data());
2697       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2698       workdir += fGridWorkingDir;
2699       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
2700       if (FileExists(executable)) gGrid->Rm(executable);
2701       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
2702       TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
2703    } 
2704 }
2705
2706 //______________________________________________________________________________
2707 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2708 {
2709 // Write the production file to be submitted by LPM manager. The format is:
2710 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2711 // Next lines: full_path_to_dataset XXX (XXX is a string)
2712 // To submit, one has to: submit jdl XXX for all lines
2713    ofstream out;
2714    out.open(filename, ios::out);
2715    if (out.bad()) {
2716       Error("WriteProductionFile", "Bad file name: %s", filename);
2717       return;
2718    }
2719    TString workdir = gGrid->GetHomeDirectory();
2720    workdir += fGridWorkingDir;
2721    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2722    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2723    out << locjdl << " " << njobspermaster << endl;
2724    Int_t nmasterjobs = fInputFiles->GetEntries();
2725    for (Int_t i=0; i<nmasterjobs; i++) {
2726       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2727       runOutDir.ReplaceAll(".xml", "");
2728       if (fOutputToRunNo)
2729          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
2730       else
2731          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2732    }
2733    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
2734    if (FileExists(filename)) gGrid->Rm(filename);
2735    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
2736 }
2737
2738 //______________________________________________________________________________
2739 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
2740 {
2741 // Generate the alien validation script.
2742    // Generate the validation script
2743    TObjString *os;
2744    TString validationScript = fExecutable;
2745    if (merge) validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
2746    else       validationScript.ReplaceAll(".sh", "_validation.sh");
2747    if (!Connect()) {
2748       Error("WriteValidationScript", "Alien connection required");
2749       return;
2750    }
2751    TString out_stream = "";
2752    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2753    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2754       ofstream out;
2755       out.open(validationScript, ios::out);
2756       out << "#!/bin/bash" << endl;
2757       out << "##################################################" << endl;
2758       out << "validateout=`dirname $0`" << endl;
2759       out << "validatetime=`date`" << endl;
2760       out << "validated=\"0\";" << endl;
2761       out << "error=0" << endl;
2762       out << "if [ -z $validateout ]" << endl;
2763       out << "then" << endl;
2764       out << "    validateout=\".\"" << endl;
2765       out << "fi" << endl << endl;
2766       out << "cd $validateout;" << endl;
2767       out << "validateworkdir=`pwd`;" << endl << endl;
2768       out << "echo \"*******************************************************\"" << out_stream << endl;
2769       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
2770       out << "" << endl;
2771       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
2772       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
2773       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
2774       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2775       out << "ls -la ./"  << out_stream << endl;
2776       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
2777       out << "##################################################" << endl;
2778
2779       out << "" << endl;
2780       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2781       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2782       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2783       out << "" << endl;
2784
2785       out << "if [ ! -f stderr ] ; then" << endl;
2786       out << "   error=1" << endl;
2787       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
2788       out << "   echo \"Error = $error\" " << out_stream << endl;
2789       out << "fi" << endl;
2790
2791       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2792       out << "   error=1" << endl;
2793       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
2794       out << "   echo \"$parArch\" " << out_stream << endl;
2795       out << "   echo \"Error = $error\" " << out_stream << endl;
2796       out << "fi" << endl;
2797
2798       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2799       out << "   error=1" << endl;
2800       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
2801       out << "   echo \"$segViol\" " << out_stream << endl;
2802       out << "   echo \"Error = $error\" " << out_stream << endl;
2803       out << "fi" << endl;
2804
2805       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2806       out << "   error=1" << endl;
2807       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
2808       out << "   echo \"$segFault\" " << out_stream << endl;
2809       out << "   echo \"Error = $error\" " << out_stream << endl;
2810       out << "fi" << endl;
2811
2812       // Part dedicated to the specific analyses running into the train
2813
2814       TObjArray *arr = fOutputFiles.Tokenize(" ");
2815       TIter next1(arr);
2816       TString output_file;
2817       while ((os=(TObjString*)next1())) { 
2818          output_file = os->GetString();
2819          Int_t index = output_file.Index("@");
2820          if (index > 0) output_file.Remove(index);
2821          if (merge && fMergeExcludes.Contains(output_file)) continue;
2822          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2823          out << "   error=1" << endl;
2824          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
2825          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2826          out << "fi" << endl;
2827       }   
2828       delete arr;
2829       out << "if ! [ -f outputs_valid ] ; then" << endl;
2830       out << "   error=1" << endl;
2831       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2832       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2833       out << "fi" << endl;
2834       
2835       out << "if [ $error = 0 ] ; then" << endl;
2836       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
2837       out << "fi" << endl;
2838
2839       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2840       out << "echo \"*******************************************************\""  << out_stream << endl;
2841       out << "cd -" << endl;
2842       out << "exit $error" << endl;
2843    }    
2844    Bool_t copy = kTRUE;
2845    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2846    if (copy) {
2847       CdWork();
2848       TString workdir = gGrid->GetHomeDirectory();
2849       workdir += fGridWorkingDir;
2850       Info("CreateJDL", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
2851       if (FileExists(validationScript)) gGrid->Rm(validationScript);
2852       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
2853    } 
2854 }