]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
removed unnecessary struct memeber fTime
[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 "AliAnalysisAlien.h"
24
25 #include "Riostream.h"
26 #include "TEnv.h"
27 #include "TKey.h"
28 #include "TBits.h"
29 #include "TError.h"
30 #include "TROOT.h"
31 #include "TSystem.h"
32 #include "TFile.h"
33 #include "TFileCollection.h"
34 #include "TChain.h"
35 #include "TObjString.h"
36 #include "TObjArray.h"
37 #include "TGrid.h"
38 #include "TGridResult.h"
39 #include "TGridCollection.h"
40 #include "TGridJDL.h"
41 #include "TGridJobStatusList.h"
42 #include "TGridJobStatus.h"
43 #include "TFileMerger.h"
44 #include "AliAnalysisManager.h"
45 #include "AliVEventHandler.h"
46 #include "AliAnalysisDataContainer.h"
47 #include "AliMultiInputEventHandler.h"
48
49 ClassImp(AliAnalysisAlien)
50 #if 0
51 ;
52 #endif  
53
54 namespace {
55   Bool_t copyLocal2Alien(const char* where, const char* loc, const char* rem)
56   {
57     TString sl(Form("file:%s", loc));
58     TString sr(Form("alien://%s", rem));
59     Bool_t ret = TFile::Cp(sl, sr);
60     if (!ret) { 
61       Warning(where, "Failed to copy %s to %s", sl.Data(), sr.Data());
62     }
63     return ret;
64   }
65 }
66     
67 //______________________________________________________________________________
68 AliAnalysisAlien::AliAnalysisAlien()
69                  :AliAnalysisGrid(),
70                   fGridJDL(NULL),
71                   fMergingJDL(NULL),
72                   fPrice(0),
73                   fTTL(0),
74                   fSplitMaxInputFileNumber(0),
75                   fMaxInitFailed(0),
76                   fMasterResubmitThreshold(0),
77                   fNtestFiles(0),
78                   fNrunsPerMaster(0),
79                   fMaxMergeFiles(0),
80                   fMaxMergeStages(0),
81                   fNsubmitted(0),
82                   fProductionMode(0),
83                   fOutputToRunNo(0),
84                   fMergeViaJDL(0),
85                   fFastReadOption(0),
86                   fOverwriteMode(1),
87                   fNreplicas(2),
88                   fNproofWorkers(0),
89                   fNproofWorkersPerSlave(0),
90                   fProofReset(0),
91                   fRunNumbers(),
92                   fExecutable(),
93                   fExecutableCommand(),
94                   fArguments(),
95                   fExecutableArgs(),
96                   fAnalysisMacro(),
97                   fAnalysisSource(),
98                   fValidationScript(),
99                   fAdditionalRootLibs(),
100                   fAdditionalLibs(),
101                   fSplitMode(),
102                   fAPIVersion(),
103                   fROOTVersion(),
104                   fAliROOTVersion(),
105                   fExternalPackages(),
106                   fUser(),
107                   fGridWorkingDir(),
108                   fGridDataDir(),
109                   fDataPattern(),
110                   fGridOutputDir(),
111                   fOutputArchive(),
112                   fOutputFiles(),
113                   fInputFormat(),
114                   fDatasetName(),
115                   fJDLName(),
116                   fTerminateFiles(),
117                             fMergeExcludes(),
118                   fIncludePath(),
119                   fCloseSE(),
120                   fFriendChainName(),
121                   fJobTag(),
122                   fOutputSingle(),
123                   fRunPrefix(),
124                   fProofCluster(),
125                   fProofDataSet(),
126                   fFileForTestMode(),
127                   fRootVersionForProof(),
128                   fAliRootMode(),
129                   fMergeDirName(),
130                   fInputFiles(0),
131                   fPackages(0),
132                   fProofParam()
133 {
134 // Dummy ctor.
135    SetDefaults();
136 }
137
138 //______________________________________________________________________________
139 AliAnalysisAlien::AliAnalysisAlien(const char *name)
140                  :AliAnalysisGrid(name),
141                   fGridJDL(NULL),
142                   fMergingJDL(NULL),
143                   fPrice(0),
144                   fTTL(0),
145                   fSplitMaxInputFileNumber(0),
146                   fMaxInitFailed(0),
147                   fMasterResubmitThreshold(0),
148                   fNtestFiles(0),
149                   fNrunsPerMaster(0),
150                   fMaxMergeFiles(0),
151                   fMaxMergeStages(0),
152                   fNsubmitted(0),
153                   fProductionMode(0),
154                   fOutputToRunNo(0),
155                   fMergeViaJDL(0),
156                   fFastReadOption(0),
157                   fOverwriteMode(1),
158                   fNreplicas(2),
159                   fNproofWorkers(0),
160                   fNproofWorkersPerSlave(0),
161                   fProofReset(0),
162                   fRunNumbers(),
163                   fExecutable(),
164                   fExecutableCommand(),
165                   fArguments(),
166                   fExecutableArgs(),
167                   fAnalysisMacro(),
168                   fAnalysisSource(),
169                   fValidationScript(),
170                   fAdditionalRootLibs(),
171                   fAdditionalLibs(),
172                   fSplitMode(),
173                   fAPIVersion(),
174                   fROOTVersion(),
175                   fAliROOTVersion(),
176                   fExternalPackages(),
177                   fUser(),
178                   fGridWorkingDir(),
179                   fGridDataDir(),
180                   fDataPattern(),
181                   fGridOutputDir(),
182                   fOutputArchive(),
183                   fOutputFiles(),
184                   fInputFormat(),
185                   fDatasetName(),
186                   fJDLName(),
187                   fTerminateFiles(),
188                   fMergeExcludes(),
189                   fIncludePath(),
190                   fCloseSE(),
191                   fFriendChainName(),
192                   fJobTag(),
193                   fOutputSingle(),
194                   fRunPrefix(),
195                   fProofCluster(),
196                   fProofDataSet(),
197                   fFileForTestMode(),
198                   fRootVersionForProof(),
199                   fAliRootMode(),
200                   fMergeDirName(),
201                   fInputFiles(0),
202                   fPackages(0),
203                   fProofParam()
204 {
205 // Default ctor.
206    SetDefaults();
207 }
208
209 //______________________________________________________________________________
210 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
211                  :AliAnalysisGrid(other),
212                   fGridJDL(NULL),
213                   fMergingJDL(NULL),
214                   fPrice(other.fPrice),
215                   fTTL(other.fTTL),
216                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
217                   fMaxInitFailed(other.fMaxInitFailed),
218                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
219                   fNtestFiles(other.fNtestFiles),
220                   fNrunsPerMaster(other.fNrunsPerMaster),
221                   fMaxMergeFiles(other.fMaxMergeFiles),
222                   fMaxMergeStages(other.fMaxMergeStages),
223                   fNsubmitted(other.fNsubmitted),
224                   fProductionMode(other.fProductionMode),
225                   fOutputToRunNo(other.fOutputToRunNo),
226                   fMergeViaJDL(other.fMergeViaJDL),
227                   fFastReadOption(other.fFastReadOption),
228                   fOverwriteMode(other.fOverwriteMode),
229                   fNreplicas(other.fNreplicas),
230                   fNproofWorkers(other.fNproofWorkers),
231                   fNproofWorkersPerSlave(other.fNproofWorkersPerSlave),
232                   fProofReset(other.fProofReset),
233                   fRunNumbers(other.fRunNumbers),
234                   fExecutable(other.fExecutable),
235                   fExecutableCommand(other.fExecutableCommand),
236                   fArguments(other.fArguments),
237                   fExecutableArgs(other.fExecutableArgs),
238                   fAnalysisMacro(other.fAnalysisMacro),
239                   fAnalysisSource(other.fAnalysisSource),
240                   fValidationScript(other.fValidationScript),
241                   fAdditionalRootLibs(other.fAdditionalRootLibs),
242                   fAdditionalLibs(other.fAdditionalLibs),
243                   fSplitMode(other.fSplitMode),
244                   fAPIVersion(other.fAPIVersion),
245                   fROOTVersion(other.fROOTVersion),
246                   fAliROOTVersion(other.fAliROOTVersion),
247                   fExternalPackages(other.fExternalPackages),
248                   fUser(other.fUser),
249                   fGridWorkingDir(other.fGridWorkingDir),
250                   fGridDataDir(other.fGridDataDir),
251                   fDataPattern(other.fDataPattern),
252                   fGridOutputDir(other.fGridOutputDir),
253                   fOutputArchive(other.fOutputArchive),
254                   fOutputFiles(other.fOutputFiles),
255                   fInputFormat(other.fInputFormat),
256                   fDatasetName(other.fDatasetName),
257                   fJDLName(other.fJDLName),
258                   fTerminateFiles(other.fTerminateFiles),
259                   fMergeExcludes(other.fMergeExcludes),
260                   fIncludePath(other.fIncludePath),
261                   fCloseSE(other.fCloseSE),
262                   fFriendChainName(other.fFriendChainName),
263                   fJobTag(other.fJobTag),
264                   fOutputSingle(other.fOutputSingle),
265                   fRunPrefix(other.fRunPrefix),
266                   fProofCluster(other.fProofCluster),
267                   fProofDataSet(other.fProofDataSet),
268                   fFileForTestMode(other.fFileForTestMode),
269                   fRootVersionForProof(other.fRootVersionForProof),
270                   fAliRootMode(other.fAliRootMode),
271                   fMergeDirName(other.fMergeDirName),
272                   fInputFiles(0),
273                   fPackages(0),
274                   fProofParam()
275 {
276 // Copy ctor.
277    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
278    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
279    fRunRange[0] = other.fRunRange[0];
280    fRunRange[1] = other.fRunRange[1];
281    if (other.fInputFiles) {
282       fInputFiles = new TObjArray();
283       TIter next(other.fInputFiles);
284       TObject *obj;
285       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
286       fInputFiles->SetOwner();
287    }   
288    if (other.fPackages) {
289       fPackages = new TObjArray();
290       TIter next(other.fPackages);
291       TObject *obj;
292       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
293       fPackages->SetOwner();
294    }   
295 }
296
297 //______________________________________________________________________________
298 AliAnalysisAlien::~AliAnalysisAlien()
299 {
300 // Destructor.
301    if (fGridJDL) delete fGridJDL;
302    if (fMergingJDL) delete fMergingJDL;
303    if (fInputFiles) delete fInputFiles;
304    if (fPackages) delete fPackages;
305    fProofParam.DeleteAll();
306 }   
307
308 //______________________________________________________________________________
309 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
310 {
311 // Assignment.
312    if (this != &other) {
313       AliAnalysisGrid::operator=(other);
314       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
315       fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
316       fPrice                   = other.fPrice;
317       fTTL                     = other.fTTL;
318       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
319       fMaxInitFailed           = other.fMaxInitFailed;
320       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
321       fNtestFiles              = other.fNtestFiles;
322       fNrunsPerMaster          = other.fNrunsPerMaster;
323       fMaxMergeFiles           = other.fMaxMergeFiles;
324       fMaxMergeStages          = other.fMaxMergeStages;
325       fNsubmitted              = other.fNsubmitted;
326       fProductionMode          = other.fProductionMode;
327       fOutputToRunNo           = other.fOutputToRunNo;
328       fMergeViaJDL             = other.fMergeViaJDL;
329       fFastReadOption          = other.fFastReadOption;
330       fOverwriteMode           = other.fOverwriteMode;
331       fNreplicas               = other.fNreplicas;
332       fNproofWorkers           = other.fNproofWorkers;
333       fNproofWorkersPerSlave   = other.fNproofWorkersPerSlave;
334       fProofReset              = other.fProofReset;
335       fRunNumbers              = other.fRunNumbers;
336       fExecutable              = other.fExecutable;
337       fExecutableCommand       = other.fExecutableCommand;
338       fArguments               = other.fArguments;
339       fExecutableArgs          = other.fExecutableArgs;
340       fAnalysisMacro           = other.fAnalysisMacro;
341       fAnalysisSource          = other.fAnalysisSource;
342       fValidationScript        = other.fValidationScript;
343       fAdditionalRootLibs      = other.fAdditionalRootLibs;
344       fAdditionalLibs          = other.fAdditionalLibs;
345       fSplitMode               = other.fSplitMode;
346       fAPIVersion              = other.fAPIVersion;
347       fROOTVersion             = other.fROOTVersion;
348       fAliROOTVersion          = other.fAliROOTVersion;
349       fExternalPackages        = other.fExternalPackages;
350       fUser                    = other.fUser;
351       fGridWorkingDir          = other.fGridWorkingDir;
352       fGridDataDir             = other.fGridDataDir;
353       fDataPattern             = other.fDataPattern;
354       fGridOutputDir           = other.fGridOutputDir;
355       fOutputArchive           = other.fOutputArchive;
356       fOutputFiles             = other.fOutputFiles;
357       fInputFormat             = other.fInputFormat;
358       fDatasetName             = other.fDatasetName;
359       fJDLName                 = other.fJDLName;
360       fTerminateFiles          = other.fTerminateFiles;
361       fMergeExcludes           = other.fMergeExcludes;
362       fIncludePath             = other.fIncludePath;
363       fCloseSE                 = other.fCloseSE;
364       fFriendChainName         = other.fFriendChainName;
365       fJobTag                  = other.fJobTag;
366       fOutputSingle            = other.fOutputSingle;
367       fRunPrefix               = other.fRunPrefix;
368       fProofCluster            = other.fProofCluster;
369       fProofDataSet            = other.fProofDataSet;
370       fFileForTestMode         = other.fFileForTestMode;
371       fRootVersionForProof     = other.fRootVersionForProof;
372       fAliRootMode             = other.fAliRootMode;
373       fMergeDirName            = other.fMergeDirName;
374       if (other.fInputFiles) {
375          fInputFiles = new TObjArray();
376          TIter next(other.fInputFiles);
377          TObject *obj;
378          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
379          fInputFiles->SetOwner();
380       }   
381       if (other.fPackages) {
382          fPackages = new TObjArray();
383          TIter next(other.fPackages);
384          TObject *obj;
385          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
386          fPackages->SetOwner();
387       }   
388    }
389    return *this;
390 }
391
392 //______________________________________________________________________________
393 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
394 {
395 // Set the run number format. Can be a prefix or a format like "%09d"
396    fRunPrefix = prefix;
397    if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
398 }   
399
400 //______________________________________________________________________________
401 void AliAnalysisAlien::AddIncludePath(const char *path)
402 {
403 // Add include path in the remote analysis macro.
404    TString p(path);
405    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
406    else                  fIncludePath += Form("-I%s ", path);
407 }
408
409 //______________________________________________________________________________
410 void AliAnalysisAlien::AddRunNumber(Int_t run)
411 {
412 // Add a run number to the list of runs to be processed.
413    if (fRunNumbers.Length()) fRunNumbers += " ";
414    fRunNumbers += Form(fRunPrefix.Data(), run);
415 }   
416
417 //______________________________________________________________________________
418 void AliAnalysisAlien::AddRunList(const char* runList)
419 {
420 // Add several runs into the list of runs; they are expected to be separated by a blank character.  
421   TString    sList = runList;
422   TObjArray *list  = sList.Tokenize(" ");
423   Int_t n = list->GetEntries();
424   for (Int_t i = 0; i < n; i++) {
425     TObjString *os = (TObjString*)list->At(i);
426     AddRunNumber(os->GetString().Atoi());
427   }
428   delete list;
429 }
430
431 //______________________________________________________________________________
432 void AliAnalysisAlien::AddRunNumber(const char* run)
433 {
434 // Add a run number to the list of runs to be processed.
435    TString runs = run;
436    TObjString *os;
437    TObjArray *arr = runs.Tokenize(" ");
438    TIter next(arr);
439    TString prefix; 
440    prefix.Append(fRunPrefix, fRunPrefix.Index("%d"));
441    while ((os=(TObjString*)next())){
442        if (fRunNumbers.Length()) fRunNumbers += " ";
443        fRunNumbers += Form("%s%s", prefix.Data(), os->GetString().Data());
444    }
445    delete arr;
446 }   
447
448 //______________________________________________________________________________
449 void AliAnalysisAlien::AddDataFile(const char *lfn)
450 {
451 // Adds a data file to the input to be analysed. The file should be a valid LFN
452 // or point to an existing file in the alien workdir.
453    if (!fInputFiles) fInputFiles = new TObjArray();
454    fInputFiles->Add(new TObjString(lfn));
455 }
456
457 //______________________________________________________________________________
458 void AliAnalysisAlien::AddExternalPackage(const char *package)
459 {
460 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
461    if (fExternalPackages) fExternalPackages += " ";
462    fExternalPackages += package;
463 }   
464       
465 //______________________________________________________________________________
466 Bool_t AliAnalysisAlien::Connect()
467 {
468 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
469    if (gGrid && gGrid->IsConnected()) return kTRUE;
470    if (fProductionMode) return kTRUE;
471    if (!gGrid) {
472       Info("Connect", "Trying to connect to AliEn ...");
473       TGrid::Connect("alien://");
474    }
475    if (!gGrid || !gGrid->IsConnected()) {
476       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
477       return kFALSE;
478    }  
479    fUser = gGrid->GetUser();
480    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
481    return kTRUE;
482 }
483
484 //______________________________________________________________________________
485 void AliAnalysisAlien::CdWork()
486 {
487 // Check validity of alien workspace. Create directory if possible.
488    if (!Connect()) {
489       Error("CdWork", "Alien connection required");
490       return;
491    } 
492    TString homedir = gGrid->GetHomeDirectory();
493    TString workdir = homedir + fGridWorkingDir;
494    if (DirectoryExists(workdir)) {
495       gGrid->Cd(workdir);
496       return;
497    }   
498    // Work directory not existing - create it
499    gGrid->Cd(homedir);
500    if (gGrid->Mkdir(workdir, "-p")) {
501       gGrid->Cd(fGridWorkingDir);
502       Info("CdWork", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
503    } else {
504       Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
505               workdir.Data(), homedir.Data());
506       fGridWorkingDir = "";
507    }          
508 }
509
510 //______________________________________________________________________________
511 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
512 {
513 // Check if file copying is possible.
514    if (fProductionMode) return kTRUE;
515    if (!Connect()) {
516       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
517       return kFALSE;
518    }
519    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
520         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
521    // Check if alien_CLOSE_SE is defined
522    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
523    if (!closeSE.IsNull()) {
524       Info("CheckFileCopy", "Your current close storage is pointing to: \
525            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
526    } else {
527       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
528    }        
529    // Check if grid directory exists.
530    if (!DirectoryExists(alienpath)) {
531       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
532       return kFALSE;
533    }
534    TFile f("plugin_test_copy", "RECREATE");
535    // User may not have write permissions to current directory 
536    if (f.IsZombie()) {
537       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
538             gSystem->WorkingDirectory());
539       return kFALSE;
540    }
541    f.Close();
542    if (FileExists(Form("alien://%s/%s",alienpath, f.GetName()))) gGrid->Rm(Form("alien://%s/%s",alienpath, f.GetName()));
543    if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, f.GetName()))) {
544       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
545            \n# 1. Make sure you have write permissions there. If this is the case: \
546            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
547            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
548            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
549            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
550       gSystem->Unlink(f.GetName());
551       return kFALSE;
552    }   
553    gSystem->Unlink(f.GetName());
554    gGrid->Rm(Form("%s%s",alienpath,f.GetName()));
555    Info("CheckFileCopy", "### ...SUCCESS ###");
556    return kTRUE;
557 }   
558
559 //______________________________________________________________________________
560 Bool_t AliAnalysisAlien::CheckInputData()
561 {
562 // Check validity of input data. If necessary, create xml files.
563    if (fProductionMode) return kTRUE;
564    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
565       if (!fGridDataDir.Length()) {
566          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
567          return kFALSE;
568       }
569       if (fMergeViaJDL) {
570          Error("CheckInputData", "Merging via jdl works only with run numbers, run range or provided xml");
571          return kFALSE;
572       }   
573       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
574       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
575          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
576       return kTRUE;
577    }
578    // Process declared files
579    Bool_t isCollection = kFALSE;
580    Bool_t isXml = kFALSE;
581    Bool_t useTags = kFALSE;
582    Bool_t checked = kFALSE;
583    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
584    TString file;
585    TString workdir = gGrid->GetHomeDirectory();
586    workdir += fGridWorkingDir;
587    if (fInputFiles) {
588       TObjString *objstr;
589       TIter next(fInputFiles);
590       while ((objstr=(TObjString*)next())) {
591          file = workdir;
592          file += "/";
593          file += objstr->GetString();
594          // Store full lfn path
595          if (FileExists(file)) objstr->SetString(file);
596          else {
597             file = objstr->GetName();
598             if (!FileExists(objstr->GetName())) {
599                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
600                      objstr->GetName(), workdir.Data());
601                return kFALSE;
602             }         
603          }
604          Bool_t iscoll, isxml, usetags;
605          CheckDataType(file, iscoll, isxml, usetags);
606          if (!checked) {
607             checked = kTRUE;
608             isCollection = iscoll;
609             isXml = isxml;
610             useTags = usetags;
611             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
612          } else {
613             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
614                Error("CheckInputData", "Some conflict was found in the types of inputs");
615                return kFALSE;
616             } 
617          }
618       }
619    }
620    // Process requested run numbers
621    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
622    // Check validity of alien data directory
623    if (!fGridDataDir.Length()) {
624       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
625       return kFALSE;
626    }
627    if (!DirectoryExists(fGridDataDir)) {
628       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
629       return kFALSE;
630    }
631    if (isCollection) {
632       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
633       return kFALSE;   
634    }
635    
636    if (checked && !isXml) {
637       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
638       return kFALSE;   
639    }
640    // Check validity of run number(s)
641    TObjArray *arr;
642    TObjString *os;
643    TString format;
644    Int_t nruns = 0;
645    TString schunk, schunk2;
646    TString path;
647    if (!checked) {
648       checked = kTRUE;
649       useTags = fDataPattern.Contains("tag");
650       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
651    }   
652    if (useTags != fDataPattern.Contains("tag")) {
653       Error("CheckInputData", "Cannot mix input files using/not using tags");
654       return kFALSE;
655    }
656    if (fRunNumbers.Length()) {
657       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
658       arr = fRunNumbers.Tokenize(" ");
659       TIter next(arr);
660       while ((os=(TObjString*)next())) {
661          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
662          if (!DirectoryExists(path)) {
663             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
664             continue;
665          }
666          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
667          TString msg = "\n#####   file: ";
668          msg += path;
669          msg += " type: xml_collection;";
670          if (useTags) msg += " using_tags: Yes";
671          else          msg += " using_tags: No";
672          Info("CheckDataType", "%s", msg.Data());
673          if (fNrunsPerMaster<2) {
674             AddDataFile(Form("%s.xml", os->GetString().Data()));
675          } else {
676             nruns++;
677             if (((nruns-1)%fNrunsPerMaster) == 0) {
678                schunk = os->GetString();
679             }   
680             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
681             schunk += Form("_%s.xml", os->GetString().Data());
682             AddDataFile(schunk);
683          }   
684       }
685       delete arr;   
686    } else {
687       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
688       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
689          format = Form("%%s/%s ", fRunPrefix.Data());
690          path = Form(format.Data(), fGridDataDir.Data(), irun);
691          if (!DirectoryExists(path)) {
692             continue;
693          }
694          format = Form("%%s/%s.xml", fRunPrefix.Data());
695          path = Form(format.Data(), workdir.Data(),irun);
696          TString msg = "\n#####   file: ";
697          msg += path;
698          msg += " type: xml_collection;";
699          if (useTags) msg += " using_tags: Yes";
700          else          msg += " using_tags: No";
701          Info("CheckDataType", "%s", msg.Data());
702          if (fNrunsPerMaster<2) {
703             format = Form("%s.xml", fRunPrefix.Data());
704             AddDataFile(Form(format.Data(),irun));
705          } else {
706             nruns++;
707             if (((nruns-1)%fNrunsPerMaster) == 0) {
708                schunk = Form(fRunPrefix.Data(),irun);
709             }
710             format = Form("_%s.xml", fRunPrefix.Data());
711             schunk2 = Form(format.Data(), irun);
712             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
713             schunk += schunk2;
714             AddDataFile(schunk);
715          }   
716       }
717       if (!fInputFiles) {
718          schunk += schunk2;
719          AddDataFile(schunk);
720       }   
721    }
722    return kTRUE;      
723 }   
724
725 //______________________________________________________________________________
726 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
727 {
728 // Create dataset for the grid data directory + run number.
729    const Int_t gMaxEntries = 15000;
730    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
731    if (!Connect()) {
732       Error("CreateDataset", "Cannot create dataset with no grid connection");
733       return kFALSE;
734    }   
735
736    // Cd workspace
737    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
738    TString workdir = gGrid->GetHomeDirectory();
739    workdir += fGridWorkingDir;
740
741    // Compose the 'find' command arguments
742    TString format;
743    TString command;
744    TString options = "-x collection ";
745    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
746    else options += Form("-l %d ", gMaxEntries);  // Protection for the find command
747    TString conditions = "";
748    Int_t nstart = 0;
749    Int_t ncount = 0;
750    Int_t stage = 0;
751    TString file;
752    TString path;
753    Int_t nruns = 0;
754    TString schunk, schunk2;
755    TGridCollection *cbase=0, *cadd=0;
756    if (!fRunNumbers.Length() && !fRunRange[0]) {
757       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
758       // Make a single data collection from data directory.
759       path = fGridDataDir;
760       if (!DirectoryExists(path)) {
761          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
762          return kFALSE;
763       }   
764 //      CdWork();
765       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
766       else file = Form("%s.xml", gSystem->BaseName(path));
767       while (1) {
768          ncount = 0;
769          stage++;
770          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
771             command = "find ";
772             command += Form("%s -o %d ",options.Data(), nstart);
773             command += path;
774             command += " ";
775             command += pattern;
776             command += conditions;
777             printf("command: %s\n", command.Data());
778             TGridResult *res = gGrid->Command(command);
779             if (res) delete res;
780             // Write standard output to file
781             gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage, file.Data()));
782             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
783             Bool_t nullFile = kFALSE;
784             if (!hasGrep) {
785                 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
786             } else {
787                nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
788                if (nullFile) {
789                   Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
790                   gSystem->Exec("rm -f __tmp*");
791                   return kFALSE;
792                }
793                TString line;
794                ifstream in;
795                in.open("__tmp__");
796                in >> line;
797                in.close();
798                gSystem->Exec("rm -f __tmp__");
799                ncount = line.Atoi();
800             }         
801          }
802          if (ncount == gMaxEntries) {
803             Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
804             cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
805             if (!cbase) cbase = cadd;
806             else {
807                cbase->Add(cadd);
808                delete cadd;
809             }   
810             nstart += ncount;
811          } else {
812             if (cbase) {
813                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
814                printf("... please wait - TAlienCollection::Add() scales badly...\n");
815                cbase->Add(cadd);
816                delete cadd;
817                cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
818                delete cbase; cbase = 0;               
819             } else {
820                TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
821             }
822             gSystem->Exec("rm -f __tmp*");   
823             Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
824             break;
825          }
826       }
827       Bool_t fileExists = FileExists(file);
828       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
829          // Copy xml file to alien space
830          if (fileExists) gGrid->Rm(file);
831          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
832          if (!FileExists(file)) {
833             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
834             return kFALSE;
835          }
836          // Update list of files to be processed.
837       }
838       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
839       return kTRUE;
840    }   
841    // Several runs
842    Bool_t nullResult = kTRUE;
843    if (fRunNumbers.Length()) {
844       TObjArray *arr = fRunNumbers.Tokenize(" ");
845       TObjString *os;
846       TIter next(arr);
847       while ((os=(TObjString*)next())) {
848          nstart = 0;
849          stage = 0;
850          path = Form("%s/%s/ ", fGridDataDir.Data(), os->GetString().Data());
851          if (!DirectoryExists(path)) continue;
852 //         CdWork();
853          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
854          else file = Form("%s.xml", os->GetString().Data());
855          // If local collection file does not exist, create it via 'find' command.
856          while (1) {
857             ncount = 0;
858             stage++;
859             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
860                command = "find ";
861                command +=  Form("%s -o %d ",options.Data(), nstart);
862                command += path;
863                command += pattern;
864                command += conditions;
865                TGridResult *res = gGrid->Command(command);
866                if (res) delete res;
867                // Write standard output to file
868                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
869                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
870                Bool_t nullFile = kFALSE;
871                if (!hasGrep) {
872                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
873                } else {
874                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
875                   if (nullFile) {
876                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
877                      gSystem->Exec("rm -f __tmp*");
878                      fRunNumbers.ReplaceAll(os->GetString().Data(), "");
879                      break;
880                   }   
881                   TString line;
882                   ifstream in;
883                   in.open("__tmp__");
884                   in >> line;
885                   in.close();
886                   gSystem->Exec("rm -f __tmp__");   
887                   ncount = line.Atoi();
888                }
889                nullResult = kFALSE;         
890             }
891             if (ncount == gMaxEntries) {
892                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
893                if (fNrunsPerMaster > 1) {
894                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
895                           file.Data(),gMaxEntries);
896                   return kFALSE;
897                }           
898                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
899                if (!cbase) cbase = cadd;
900                else {
901                   cbase->Add(cadd);
902                   delete cadd;
903                }   
904                nstart += ncount;
905             } else {
906                if (cbase && fNrunsPerMaster<2) {
907                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
908                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
909                   cbase->Add(cadd);
910                   delete cadd;
911                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
912                   delete cbase; cbase = 0;               
913                } else {
914                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
915                }
916                gSystem->Exec("rm -f __tmp*");   
917                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
918                break;
919             }
920          }   
921          if (TestBit(AliAnalysisGrid::kTest)) break;
922          // Check if there is one run per master job.
923          if (fNrunsPerMaster<2) {
924             if (FileExists(file)) {
925                if (fOverwriteMode) gGrid->Rm(file);
926                else {
927                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
928                   continue;
929                }   
930             }        
931             // Copy xml file to alien space
932             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
933             if (!FileExists(file)) {
934                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
935                delete arr;
936                return kFALSE;
937             }
938          } else {
939             nruns++;
940             if (((nruns-1)%fNrunsPerMaster) == 0) {
941                schunk = os->GetString();
942                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
943             } else {
944                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
945                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
946                cbase->Add(cadd);
947                delete cadd;
948             }
949             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
950                continue;
951             }   
952             schunk += Form("_%s.xml", os->GetString().Data());
953             if (FileExists(schunk)) {               
954                if (fOverwriteMode) gGrid->Rm(file);
955                else {
956                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
957                   continue;
958                }   
959             }        
960             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
961             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
962             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
963             if (!FileExists(schunk)) {
964                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
965                delete arr;
966                return kFALSE;
967             }
968          }
969       }   
970       delete arr;
971       if (nullResult) {
972          Error("CreateDataset", "No valid dataset corresponding to the query!");
973          return kFALSE;
974       }
975    } else {
976       // Process a full run range.
977       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
978          format = Form("%%s/%s ", fRunPrefix.Data());
979          nstart = 0;
980          stage = 0;
981          path = Form(format.Data(), fGridDataDir.Data(), irun);
982          if (!DirectoryExists(path)) continue;
983 //         CdWork();
984          format = Form("%s.xml", fRunPrefix.Data());
985          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
986          else file = Form(format.Data(), irun);
987          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
988             if (fOverwriteMode) gGrid->Rm(file);
989             else {
990                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
991                continue;
992             }   
993          }
994          // If local collection file does not exist, create it via 'find' command.
995          while (1) {
996             ncount = 0;
997             stage++;
998             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
999                command = "find ";
1000                command +=  Form("%s -o %d ",options.Data(), nstart);
1001                command += path;
1002                command += pattern;
1003                command += conditions;
1004                TGridResult *res = gGrid->Command(command);
1005                if (res) delete res;
1006                // Write standard output to file
1007                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1008                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1009                Bool_t nullFile = kFALSE;
1010                if (!hasGrep) {
1011                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1012                } else {
1013                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1014                   if (nullFile) {
1015                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1016                      gSystem->Exec("rm -f __tmp*");
1017                      break;
1018                   }   
1019                   TString line;
1020                   ifstream in;
1021                   in.open("__tmp__");
1022                   in >> line;
1023                   in.close();
1024                   gSystem->Exec("rm -f __tmp__");   
1025                   ncount = line.Atoi();
1026                }
1027                nullResult = kFALSE;         
1028             }   
1029             if (ncount == gMaxEntries) {
1030                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1031                if (fNrunsPerMaster > 1) {
1032                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1033                           file.Data(),gMaxEntries);
1034                   return kFALSE;
1035                }           
1036                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1037                if (!cbase) cbase = cadd;
1038                else {
1039                   cbase->Add(cadd);
1040                   delete cadd;
1041                }   
1042                nstart += ncount;
1043             } else {
1044                if (cbase && fNrunsPerMaster<2) {
1045                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1046                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1047                   cbase->Add(cadd);
1048                   delete cadd;
1049                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1050                   delete cbase; cbase = 0;               
1051                } else {
1052                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1053                }
1054                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1055                break;
1056             }
1057          }   
1058          if (TestBit(AliAnalysisGrid::kTest)) break;
1059          // Check if there is one run per master job.
1060          if (fNrunsPerMaster<2) {
1061             if (FileExists(file)) {
1062                if (fOverwriteMode) gGrid->Rm(file);
1063                else {
1064                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1065                   continue;
1066                }   
1067             }        
1068             // Copy xml file to alien space
1069             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1070             if (!FileExists(file)) {
1071                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1072                return kFALSE;
1073             }
1074          } else {
1075             nruns++;
1076             // Check if the collection for the chunk exist locally.
1077             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
1078             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
1079                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
1080                else continue;
1081             }   
1082             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
1083             if (((nruns-1)%fNrunsPerMaster) == 0) {
1084                schunk = Form(fRunPrefix.Data(), irun);
1085                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1086             } else {
1087                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1088                cbase->Add(cadd);
1089                delete cadd;
1090             }
1091             format = Form("%%s_%s.xml", fRunPrefix.Data());
1092             schunk2 = Form(format.Data(), schunk.Data(), irun);
1093             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
1094                continue;
1095             }   
1096             schunk = schunk2;
1097             if (FileExists(schunk)) {
1098                if (fOverwriteMode) gGrid->Rm(schunk);
1099                else {
1100                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1101                   continue;
1102                }   
1103             }        
1104             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
1105             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1106             if (FileExists(schunk)) {
1107                if (fOverwriteMode) gGrid->Rm(schunk);
1108                else {
1109                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
1110                   continue;
1111                }   
1112             }   
1113             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1114             if (!FileExists(schunk)) {
1115                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1116                return kFALSE;
1117             }
1118          }   
1119       }
1120       if (nullResult) {
1121          Error("CreateDataset", "No valid dataset corresponding to the query!");
1122          return kFALSE;
1123       }      
1124    }      
1125    return kTRUE;
1126 }
1127
1128 //______________________________________________________________________________
1129 Bool_t AliAnalysisAlien::CreateJDL()
1130 {
1131 // Generate a JDL file according to current settings. The name of the file is 
1132 // specified by fJDLName.
1133    Bool_t error = kFALSE;
1134    TObjArray *arr = 0;
1135    Bool_t copy = kTRUE;
1136    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1137    Bool_t generate = kTRUE;
1138    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
1139    if (!Connect()) {
1140       Error("CreateJDL", "Alien connection required");
1141       return kFALSE;
1142    }   
1143    // Check validity of alien workspace
1144    TString workdir;
1145    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1146    if (!fProductionMode &&  !TestBit(AliAnalysisGrid::kTest)) CdWork();
1147    workdir += fGridWorkingDir;
1148    if (generate) {
1149       TObjString *os;
1150       if (!fInputFiles) {
1151          Error("CreateJDL()", "Define some input files for your analysis.");
1152          error = kTRUE;
1153       }
1154       // Compose list of input files   
1155       // Check if output files were defined
1156       if (!fOutputFiles.Length()) {
1157          Error("CreateJDL", "You must define at least one output file");
1158          error = kTRUE;
1159       }   
1160       // Check if an output directory was defined and valid
1161       if (!fGridOutputDir.Length()) {
1162          Error("CreateJDL", "You must define AliEn output directory");
1163          error = kTRUE;
1164       } else {
1165          if (!fProductionMode) {
1166             if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1167             if (!DirectoryExists(fGridOutputDir)) {
1168                if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1169                   Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1170                } else {
1171                   Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1172                   // error = kTRUE;
1173                }
1174             } else {
1175                Warning("CreateJDL", "#### Output directory %s exists! If this contains old data, jobs will fail with ERROR_SV !!! ###", fGridOutputDir.Data());
1176             }   
1177             gGrid->Cd(workdir);
1178          }   
1179       }   
1180       // Exit if any error up to now
1181       if (error) return kFALSE;   
1182       // Set JDL fields
1183       if (!fUser.IsNull()) {
1184          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1185          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1186       }   
1187       fGridJDL->SetExecutable(fExecutable, "This is the startup script");
1188       TString mergeExec = fExecutable;
1189       mergeExec.ReplaceAll(".sh", "_merge.sh");
1190       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1191       mergeExec.ReplaceAll(".sh", ".C");
1192       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
1193       if (!fArguments.IsNull())
1194          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1195       if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1196       else {
1197          if (fProductionMode)  fMergingJDL->SetArguments("wn.xml $4");    // xml, stage
1198          else                  fMergingJDL->SetArguments("wn.xml $2");    // xml, stage
1199      }               
1200
1201       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1202       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1203       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1204       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1205         
1206       if (fMaxInitFailed > 0) {
1207          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1208          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1209       }   
1210       if (fSplitMaxInputFileNumber > 0) {
1211          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1212          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1213       }
1214       if (!IsOneStageMerging()) {
1215          fMergingJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"",fMaxMergeFiles));
1216          fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1217       }   
1218       if (fSplitMode.Length()) {
1219          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1220          fGridJDL->SetDescription("Split", "We split per SE or file");
1221       }
1222       fMergingJDL->SetValue("Split", "\"se\""); 
1223       fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1224       if (!fAliROOTVersion.IsNull()) {
1225          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1226          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1227       }   
1228       if (!fROOTVersion.IsNull()) {
1229          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1230          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1231       }   
1232       if (!fAPIVersion.IsNull()) {
1233          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1234          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1235       }   
1236       if (!fExternalPackages.IsNull()) {
1237          arr = fExternalPackages.Tokenize(" ");
1238          TIter next(arr);
1239          while ((os=(TObjString*)next())) {
1240             TString pkgname = os->GetString();
1241             Int_t index = pkgname.Index("::");
1242             TString pkgversion = pkgname(index+2, pkgname.Length());
1243             pkgname.Remove(index);
1244             fGridJDL->AddToPackages(pkgname, pkgversion);
1245             fMergingJDL->AddToPackages(pkgname, pkgversion);
1246          }   
1247          delete arr;   
1248       }   
1249       fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1250       fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1251       fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1252       fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1253       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1254       TString analysisFile = fExecutable;
1255       analysisFile.ReplaceAll(".sh", ".root");
1256       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1257       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1258       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
1259          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
1260       if (fAdditionalLibs.Length()) {
1261          arr = fAdditionalLibs.Tokenize(" ");
1262          TIter next(arr);
1263          while ((os=(TObjString*)next())) {
1264             if (os->GetString().Contains(".so")) continue;
1265             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1266             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1267          }   
1268          delete arr;   
1269       }
1270       if (fPackages) {
1271          TIter next(fPackages);
1272          TObject *obj;
1273          while ((obj=next())) {
1274             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1275             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1276          }
1277       }
1278       if (fOutputArchive.Length()) {
1279          arr = fOutputArchive.Tokenize(" ");
1280          TIter next(arr);
1281          Bool_t first = kTRUE;
1282          const char *comment = "Files to be archived";
1283          const char *comment1 = comment;
1284          while ((os=(TObjString*)next())) {
1285             if (!first) comment = NULL;
1286             if (!os->GetString().Contains("@") && fCloseSE.Length())
1287                fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1288             else
1289                fGridJDL->AddToOutputArchive(os->GetString(), comment);
1290             first = kFALSE;   
1291          }      
1292          delete arr;
1293          // Output archive for the merging jdl
1294          TString outputArchive;
1295          if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1296             outputArchive = "log_archive.zip:std*@disk=1 ";
1297             // Add normal output files, extra files + terminate files
1298             TString files = GetListOfFiles("outextter");
1299             // Do not register merge excludes
1300             if (!fMergeExcludes.IsNull()) {
1301                arr = fMergeExcludes.Tokenize(" ");
1302                TIter next1(arr);
1303                while ((os=(TObjString*)next1())) {
1304                   files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1305                   files.ReplaceAll(os->GetString(),"");
1306                }   
1307                delete arr;
1308             }
1309             files.ReplaceAll(".root", "*.root");
1310             outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",files.Data(),fNreplicas);
1311          } else {
1312             TString files = fOutputArchive;
1313             files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1314             outputArchive = files;
1315          }   
1316          arr = outputArchive.Tokenize(" ");
1317          TIter next2(arr);
1318          comment = comment1;
1319          first = kTRUE;
1320          while ((os=(TObjString*)next2())) {
1321             if (!first) comment = NULL;
1322             TString currentfile = os->GetString();
1323             if (!currentfile.Contains("@") && fCloseSE.Length())
1324                fMergingJDL->AddToOutputArchive(Form("%s@%s",currentfile.Data(), fCloseSE.Data()), comment);
1325             else
1326                fMergingJDL->AddToOutputArchive(currentfile, comment);
1327             first = kFALSE;   
1328          }      
1329          delete arr;         
1330       }      
1331       arr = fOutputFiles.Tokenize(",");
1332       TIter next(arr);
1333       Bool_t first = kTRUE;
1334       const char *comment = "Files to be saved";
1335       while ((os=(TObjString*)next())) {
1336          // Ignore ouputs in jdl that are also in outputarchive
1337          TString sout = os->GetString();
1338          sout.ReplaceAll("*", "");
1339          sout.ReplaceAll(".root", "");
1340          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1341          if (fOutputArchive.Contains(sout)) continue;
1342          if (!first) comment = NULL;
1343          if (!os->GetString().Contains("@") && fCloseSE.Length())
1344             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1345          else
1346             fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1347          first = kFALSE;
1348          if (fMergeExcludes.Contains(sout)) continue;   
1349          if (!os->GetString().Contains("@") && fCloseSE.Length())
1350             fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1351          else
1352             fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1353       }   
1354       delete arr;
1355       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1356       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1357       TString validationScript = fValidationScript;
1358       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1359       validationScript.ReplaceAll(".sh", "_merge.sh");
1360       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1361       if (fMasterResubmitThreshold) {
1362          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1363          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1364       }   
1365       // Write a jdl with 2 input parameters: collection name and output dir name.
1366       WriteJDL(copy);
1367    }
1368    // Copy jdl to grid workspace   
1369    if (copy) {
1370       // Check if an output directory was defined and valid
1371       if (!fGridOutputDir.Length()) {
1372          Error("CreateJDL", "You must define AliEn output directory");
1373          return kFALSE;
1374       } else {
1375          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1376          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1377             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1378                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1379             } else {
1380                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1381                return kFALSE;
1382             }
1383          }
1384          gGrid->Cd(workdir);
1385       }   
1386       if (TestBit(AliAnalysisGrid::kSubmit)) {
1387          TString mergeJDLName = fExecutable;
1388          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1389          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1390          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1391          if (fProductionMode) {
1392             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1393             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1394          }   
1395          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1396          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1397          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1398          if (!copyLocal2Alien("CreateJDL", fJDLName, locjdl)) 
1399             Fatal("","Terminating");
1400 //         TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1401          if (fMergeViaJDL) {
1402             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1403 //            TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1404             if (!copyLocal2Alien("CreateJDL", mergeJDLName.Data(), locjdl1)) 
1405                Fatal("","Terminating");
1406          }   
1407       }
1408       if (fAdditionalLibs.Length()) {
1409          arr = fAdditionalLibs.Tokenize(" ");
1410          TObjString *os;
1411          TIter next(arr);
1412          while ((os=(TObjString*)next())) {
1413             if (os->GetString().Contains(".so")) continue;
1414             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1415             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1416 //            TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1417             if (!copyLocal2Alien("CreateJDL", os->GetString().Data(), 
1418                 Form("%s/%s", workdir.Data(), os->GetString().Data())))
1419               Fatal("","Terminating");
1420          }   
1421          delete arr;   
1422       }
1423       if (fPackages) {
1424          TIter next(fPackages);
1425          TObject *obj;
1426          while ((obj=next())) {
1427             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1428             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1429 //            TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1430             if (!copyLocal2Alien("CreateJDL",obj->GetName(), 
1431                 Form("%s/%s", workdir.Data(), obj->GetName()))) 
1432               Fatal("","Terminating"); 
1433          }   
1434       }      
1435    } 
1436    return kTRUE;
1437 }
1438
1439 //______________________________________________________________________________
1440 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1441 {
1442 // Writes one or more JDL's corresponding to findex. If findex is negative,
1443 // all run numbers are considered in one go (jdl). For non-negative indices
1444 // they correspond to the indices in the array fInputFiles.
1445    if (!fInputFiles) return kFALSE;
1446    TObject *os;
1447    TString workdir;
1448    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1449    workdir += fGridWorkingDir;
1450    TString stageName = "$2";
1451    if (fProductionMode) stageName = "$4";
1452    if (!fMergeDirName.IsNull()) {
1453      fMergingJDL->AddToInputDataCollection(Form("LF:$1/%s/Stage_%s.xml,nodownload",fMergeDirName.Data(),stageName.Data()), "Collection of files to be merged for current stage");
1454      fMergingJDL->SetOutputDirectory(Form("$1/%s/Stage_%s/#alien_counter_03i#",fMergeDirName.Data(),stageName.Data()), "Output directory");
1455    } else {
1456      fMergingJDL->AddToInputDataCollection(Form("LF:$1/Stage_%s.xml,nodownload",stageName.Data()), "Collection of files to be merged for current stage");
1457      fMergingJDL->SetOutputDirectory(Form("$1/Stage_%s/#alien_counter_03i#",stageName.Data()), "Output directory");
1458    }
1459    if (fProductionMode) {
1460       TIter next(fInputFiles);
1461       while ((os=next())) {
1462          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1463       }
1464       if (!fOutputToRunNo)
1465          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1466       else  
1467          fGridJDL->SetOutputDirectory(fGridOutputDir);
1468    } else {            
1469       if (!fRunNumbers.Length() && !fRunRange[0]) {
1470          // One jdl with no parameters in case input data is specified by name.
1471          TIter next(fInputFiles);
1472          while ((os=next()))
1473             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1474          if (!fOutputSingle.IsNull())
1475             fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1476          else {
1477             fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1478             fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1479          }   
1480       } else {
1481          // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1482          fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1483          if (!fOutputSingle.IsNull()) {
1484             if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1485             else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1486          } else {   
1487             fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1488          }   
1489       }
1490    }
1491       
1492    // Generate the JDL as a string
1493    TString sjdl = fGridJDL->Generate();
1494    TString sjdl1 = fMergingJDL->Generate();
1495    // Final merge jdl
1496    if (!fMergeDirName.IsNull()) {
1497      fMergingJDL->SetOutputDirectory(Form("$1/%s",fMergeDirName.Data()), "Output directory");
1498      fMergingJDL->AddToInputSandbox(Form("LF:$1/%s/Stage_%s.xml",fMergeDirName.Data(),stageName.Data()));
1499    } else {  
1500      fMergingJDL->SetOutputDirectory("$1", "Output directory");
1501      fMergingJDL->AddToInputSandbox(Form("LF:$1/Stage_%s.xml",stageName.Data()));
1502    }  
1503    TString sjdl2 = fMergingJDL->Generate();
1504    Int_t index, index1;
1505    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
1506    sjdl.ReplaceAll("(member", "\n   (member");
1507    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1508    sjdl.ReplaceAll("{", "{\n   ");
1509    sjdl.ReplaceAll("};", "\n};");
1510    sjdl.ReplaceAll("{\n   \n", "{\n");
1511    sjdl.ReplaceAll("\n\n", "\n");
1512    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1513    sjdl1.ReplaceAll("\"LF:", "\n   \"LF:");
1514    sjdl1.ReplaceAll("(member", "\n   (member");
1515    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1516    sjdl1.ReplaceAll("{", "{\n   ");
1517    sjdl1.ReplaceAll("};", "\n};");
1518    sjdl1.ReplaceAll("{\n   \n", "{\n");
1519    sjdl1.ReplaceAll("\n\n", "\n");
1520    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1521    sjdl2.ReplaceAll("\"LF:", "\n   \"LF:");
1522    sjdl2.ReplaceAll("(member", "\n   (member");
1523    sjdl2.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1524    sjdl2.ReplaceAll("{", "{\n   ");
1525    sjdl2.ReplaceAll("};", "\n};");
1526    sjdl2.ReplaceAll("{\n   \n", "{\n");
1527    sjdl2.ReplaceAll("\n\n", "\n");
1528    sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
1529    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1530    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
1531    index = sjdl.Index("JDLVariables");
1532    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1533    sjdl += "Workdirectorysize = {\"5000MB\"};";
1534    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1535    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1536    index = fJobTag.Index(":");
1537    if (index < 0) index = fJobTag.Length();
1538    TString jobTag = fJobTag;
1539    if (fProductionMode) jobTag.Insert(index,"_Stage$4");
1540    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", jobTag.Data()));
1541    if (fProductionMode) {   
1542      sjdl1.Prepend("# Generated merging jdl (production mode) \
1543                     \n# $1 = full alien path to output directory to be merged \
1544                     \n# $2 = train number \
1545                     \n# $3 = production (like LHC10b) \
1546                     \n# $4 = merging stage \
1547                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1548      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
1549      sjdl2.Prepend("# Generated merging jdl \
1550                     \n# $1 = full alien path to output directory to be merged \
1551                     \n# $2 = train number \
1552                     \n# $3 = production (like LHC10b) \
1553                     \n# $4 = merging stage \
1554                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1555    } else {
1556      sjdl1.Prepend("# Generated merging jdl \
1557                     \n# $1 = full alien path to output directory to be merged \
1558                     \n# $2 = merging stage \
1559                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1560      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
1561      sjdl2.Prepend("# Generated merging jdl \
1562                     \n# $1 = full alien path to output directory to be merged \
1563                     \n# $2 = merging stage \
1564                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1565    }
1566    index = sjdl1.Index("JDLVariables");
1567    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1568    index = sjdl2.Index("JDLVariables");
1569    if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
1570    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1571    sjdl2 += "Workdirectorysize = {\"5000MB\"};";
1572    index = sjdl2.Index("Split =");
1573    if (index>=0) {
1574       index1 = sjdl2.Index("\n", index);
1575       sjdl2.Remove(index, index1-index+1);
1576    }
1577    index = sjdl2.Index("SplitMaxInputFileNumber");
1578    if (index>=0) {
1579       index1 = sjdl2.Index("\n", index);
1580       sjdl2.Remove(index, index1-index+1);
1581    }
1582    index = sjdl2.Index("InputDataCollection");
1583    if (index>=0) {
1584       index1 = sjdl2.Index(";", index);
1585       sjdl2.Remove(index, index1-index+1);
1586    }
1587    index = sjdl2.Index("InputDataListFormat");
1588    if (index>=0) {
1589       index1 = sjdl2.Index("\n", index);
1590       sjdl2.Remove(index, index1-index+1);
1591    }
1592    index = sjdl2.Index("InputDataList");
1593    if (index>=0) {
1594       index1 = sjdl2.Index("\n", index);
1595       sjdl2.Remove(index, index1-index+1);
1596    }
1597    sjdl2.ReplaceAll("wn.xml", Form("Stage_%s.xml",stageName.Data()));
1598    // Write jdl to file
1599    ofstream out;
1600    out.open(fJDLName.Data(), ios::out);
1601    if (out.bad()) {
1602       Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
1603       return kFALSE;
1604    }
1605    out << sjdl << endl;
1606    out.close();
1607    TString mergeJDLName = fExecutable;
1608    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1609    if (fMergeViaJDL) {
1610       ofstream out1;
1611       out1.open(mergeJDLName.Data(), ios::out);
1612       if (out1.bad()) {
1613          Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
1614          return kFALSE;
1615       }
1616       out1 << sjdl1 << endl;
1617       out1.close();
1618       ofstream out2;
1619       TString finalJDL = mergeJDLName;
1620       finalJDL.ReplaceAll(".jdl", "_final.jdl");
1621       out2.open(finalJDL.Data(), ios::out);
1622       if (out2.bad()) {
1623          Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
1624          return kFALSE;
1625       }
1626       out2 << sjdl2 << endl;
1627       out2.close();
1628    }   
1629
1630    // Copy jdl to grid workspace   
1631    if (!copy) {
1632       Info("WriteJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1633    } else {
1634       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1635       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1636       TString finalJDL = mergeJDLName;
1637       finalJDL.ReplaceAll(".jdl", "_final.jdl");
1638       TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
1639       if (fProductionMode) {
1640          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1641          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1642          locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
1643       }   
1644       if (FileExists(locjdl)) gGrid->Rm(locjdl);
1645       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1646       if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
1647       Info("WriteJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1648 //      TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1649       if (!copyLocal2Alien("WriteJDL",fJDLName.Data(),locjdl.Data())) 
1650          Fatal("","Terminating");
1651       if (fMergeViaJDL) {
1652          Info("WriteJDL", "\n#####   Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
1653 //         TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1654 //         TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
1655          if (!copyLocal2Alien("WriteJDL",mergeJDLName.Data(),locjdl1.Data()))
1656             Fatal("","Terminating");
1657          if (!copyLocal2Alien("WriteJDL",finalJDL.Data(),locjdl2.Data()))
1658            Fatal("","Terminating");
1659       }   
1660    } 
1661    return kTRUE;
1662 }
1663
1664 //______________________________________________________________________________
1665 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1666 {
1667 // Returns true if file exists.
1668    if (!gGrid) return kFALSE;
1669    TString slfn = lfn;
1670    slfn.ReplaceAll("alien://","");
1671    TGridResult *res = gGrid->Ls(slfn);
1672    if (!res) return kFALSE;
1673    TMap *map = dynamic_cast<TMap*>(res->At(0));
1674    if (!map) {
1675       delete res;
1676       return kFALSE;
1677    }   
1678    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1679    if (!objs || !objs->GetString().Length()) {
1680       delete res;
1681       return kFALSE;
1682    }
1683    delete res;   
1684    return kTRUE;
1685 }
1686
1687 //______________________________________________________________________________
1688 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1689 {
1690 // Returns true if directory exists. Can be also a path.
1691    if (!gGrid) return kFALSE;
1692    // Check if dirname is a path
1693    TString dirstripped = dirname;
1694    dirstripped = dirstripped.Strip();
1695    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1696    TString dir = gSystem->BaseName(dirstripped);
1697    dir += "/";
1698    TString path = gSystem->DirName(dirstripped);
1699    TGridResult *res = gGrid->Ls(path, "-F");
1700    if (!res) return kFALSE;
1701    TIter next(res);
1702    TMap *map;
1703    TObject *obj;
1704    while ((map=dynamic_cast<TMap*>(next()))) {
1705       obj = map->GetValue("name");
1706       if (!obj) break;
1707       if (dir == obj->GetName()) {
1708          delete res;
1709          return kTRUE;
1710       }
1711    }
1712    delete res;
1713    return kFALSE;
1714 }      
1715
1716 //______________________________________________________________________________
1717 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
1718 {
1719 // Check input data type.
1720    isCollection = kFALSE;
1721    isXml = kFALSE;
1722    useTags = kFALSE;
1723    if (!gGrid) {
1724       Error("CheckDataType", "No connection to grid");
1725       return;
1726    }
1727    isCollection = IsCollection(lfn);
1728    TString msg = "\n#####   file: ";
1729    msg += lfn;
1730    if (isCollection) {
1731       msg += " type: raw_collection;";
1732    // special treatment for collections
1733       isXml = kFALSE;
1734       // check for tag files in the collection
1735       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1736       if (!res) {
1737          msg += " using_tags: No (unknown)";
1738          Info("CheckDataType", "%s", msg.Data());
1739          return;
1740       }   
1741       const char* typeStr = res->GetKey(0, "origLFN");
1742       if (!typeStr || !strlen(typeStr)) {
1743          msg += " using_tags: No (unknown)";
1744          Info("CheckDataType", "%s", msg.Data());
1745          return;
1746       }   
1747       TString file = typeStr;
1748       useTags = file.Contains(".tag");
1749       if (useTags) msg += " using_tags: Yes";
1750       else          msg += " using_tags: No";
1751       Info("CheckDataType", "%s", msg.Data());
1752       return;
1753    }
1754    TString slfn(lfn);
1755    slfn.ToLower();
1756    isXml = slfn.Contains(".xml");
1757    if (isXml) {
1758    // Open xml collection and check if there are tag files inside
1759       msg += " type: xml_collection;";
1760       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1761       if (!coll) {
1762          msg += " using_tags: No (unknown)";
1763          Info("CheckDataType", "%s", msg.Data());
1764          return;
1765       }   
1766       TMap *map = coll->Next();
1767       if (!map) {
1768          msg += " using_tags: No (unknown)";
1769          Info("CheckDataType", "%s", msg.Data());
1770          return;
1771       }   
1772       map = (TMap*)map->GetValue("");
1773       TString file;
1774       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1775       useTags = file.Contains(".tag");
1776       delete coll;
1777       if (useTags) msg += " using_tags: Yes";
1778       else          msg += " using_tags: No";
1779       Info("CheckDataType", "%s", msg.Data());
1780       return;
1781    }
1782    useTags = slfn.Contains(".tag");
1783    if (slfn.Contains(".root")) msg += " type: root file;";
1784    else                        msg += " type: unknown file;";
1785    if (useTags) msg += " using_tags: Yes";
1786    else          msg += " using_tags: No";
1787    Info("CheckDataType", "%s", msg.Data());
1788 }
1789
1790 //______________________________________________________________________________
1791 void AliAnalysisAlien::EnablePackage(const char *package)
1792 {
1793 // Enables a par file supposed to exist in the current directory.
1794    TString pkg(package);
1795    pkg.ReplaceAll(".par", "");
1796    pkg += ".par";
1797    if (gSystem->AccessPathName(pkg)) {
1798       Fatal("EnablePackage", "Package %s not found", pkg.Data());
1799       return;
1800    }
1801    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1802       Info("EnablePackage", "AliEn plugin will use .par packages");
1803    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1804    if (!fPackages) {
1805       fPackages = new TObjArray();
1806       fPackages->SetOwner();
1807    }
1808    fPackages->Add(new TObjString(pkg));
1809 }      
1810
1811 //______________________________________________________________________________
1812 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
1813 {
1814 // Make a tree from files having the location specified in fFileForTestMode. 
1815 // Inspired from JF's CreateESDChain.
1816    if (fFileForTestMode.IsNull()) {
1817       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
1818       return NULL;
1819    }
1820    if (gSystem->AccessPathName(fFileForTestMode)) {
1821       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
1822       return NULL;
1823    }   
1824    // Open the file
1825    ifstream in;
1826    in.open(fFileForTestMode);
1827    Int_t count = 0;
1828     // Read the input list of files and add them to the chain
1829     TString line;
1830     TChain *chain = new TChain(treeName);
1831     while (in.good())
1832     {
1833       in >> line;
1834       if (line.IsNull()) continue;
1835       if (count++ == fNtestFiles) break;
1836       TString esdFile(line);
1837       TFile *file = TFile::Open(esdFile);
1838       if (file) {
1839          if (!file->IsZombie()) chain->Add(esdFile);
1840          file->Close();
1841       } else {
1842          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
1843       }   
1844     }
1845     in.close();
1846     if (!chain->GetListOfFiles()->GetEntries()) {
1847        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
1848        delete chain;
1849        return NULL;
1850     }
1851 //    chain->ls();
1852     return chain;
1853 }    
1854
1855 //______________________________________________________________________________
1856 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1857 {
1858 // Get job status for all jobs with jobid>jobidstart.
1859    static char mstatus[20];
1860    mstatus[0] = '\0';
1861    nrunning = 0;
1862    nwaiting = 0;
1863    nerror   = 0;
1864    ndone    = 0;
1865    TGridJobStatusList *list = gGrid->Ps("");
1866    if (!list) return mstatus;
1867    Int_t nentries = list->GetSize();
1868    TGridJobStatus *status;
1869    Int_t pid;
1870    for (Int_t ijob=0; ijob<nentries; ijob++) {
1871       status = (TGridJobStatus *)list->At(ijob);
1872       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)%p)->GetKey(\"queueId\"));", status));
1873       if (pid<jobidstart) continue;
1874       if (pid == lastid) {
1875          gROOT->ProcessLine(Form("sprintf((char*)%p,((TAlienJobStatus*)%p)->GetKey(\"status\"));",mstatus, status));
1876       }   
1877       switch (status->GetStatus()) {
1878          case TGridJobStatus::kWAITING:
1879             nwaiting++; break;
1880          case TGridJobStatus::kRUNNING:
1881             nrunning++; break;
1882          case TGridJobStatus::kABORTED:
1883          case TGridJobStatus::kFAIL:
1884          case TGridJobStatus::kUNKNOWN:
1885             nerror++; break;
1886          case TGridJobStatus::kDONE:
1887             ndone++;
1888       }
1889    }
1890    list->Delete();
1891    delete list;
1892    return mstatus;
1893 }
1894
1895 //______________________________________________________________________________
1896 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1897 {
1898 // Returns true if file is a collection. Functionality duplicated from
1899 // TAlien::Type() because we don't want to directly depend on TAlien.
1900    if (!gGrid) {
1901       Error("IsCollection", "No connection to grid");
1902       return kFALSE;
1903    }
1904    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1905    if (!res) return kFALSE;
1906    const char* typeStr = res->GetKey(0, "type");
1907    if (!typeStr || !strlen(typeStr)) return kFALSE;
1908    if (!strcmp(typeStr, "collection")) return kTRUE;
1909    delete res;
1910    return kFALSE;
1911 }   
1912
1913 //______________________________________________________________________________
1914 Bool_t AliAnalysisAlien::IsSingleOutput() const
1915 {
1916 // Check if single-ouput option is on.
1917    return (!fOutputSingle.IsNull());
1918 }
1919    
1920 //______________________________________________________________________________
1921 void AliAnalysisAlien::Print(Option_t *) const
1922 {
1923 // Print current plugin settings.
1924    printf("### AliEn analysis plugin current settings ###\n");
1925    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1926    if (mgr && mgr->IsProofMode()) {
1927       TString proofType = "=   PLUGIN IN PROOF MODE ON CLUSTER:_________________";
1928       if (TestBit(AliAnalysisGrid::kTest))
1929          proofType = "=   PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
1930       printf("%s %s\n", proofType.Data(), fProofCluster.Data());
1931       if (!fProofDataSet.IsNull())
1932       printf("=   Requested data set:___________________________ %s\n", fProofDataSet.Data());
1933       if (fProofReset==1)
1934       printf("=   Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
1935       if (fProofReset>1)   
1936       printf("=   Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
1937       if (!fRootVersionForProof.IsNull())
1938       printf("=   ROOT version requested________________________ %s\n", fRootVersionForProof.Data());
1939       else
1940       printf("=   ROOT version requested________________________ default\n");
1941       printf("=   AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
1942       if (!fAliRootMode.IsNull())
1943       printf("=   Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());  
1944       if (fNproofWorkers)
1945       printf("=   Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
1946       if  (fNproofWorkersPerSlave)
1947       printf("=   Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
1948       if (TestSpecialBit(kClearPackages))
1949       printf("=   ClearPackages requested...\n");
1950       if (fIncludePath.Data())
1951       printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1952       printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1953       if (fPackages && fPackages->GetEntries()) {
1954          TIter next(fPackages);
1955          TObject *obj;
1956          TString list;
1957          while ((obj=next())) list += obj->GetName();
1958          printf("=   Par files to be used: ________________________ %s\n", list.Data());
1959       } 
1960       if (TestSpecialBit(kProofConnectGrid))
1961       printf("=   Requested PROOF connection to grid\n");
1962       return;
1963    }
1964    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
1965    if (fOverwriteMode) {
1966       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
1967             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
1968    }
1969    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
1970    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
1971    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1972    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1973    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1974    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1975    if (fUser.Length()) 
1976    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1977    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1978    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1979    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1980    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1981    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1982    if (fRunNumbers.Length()) 
1983    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1984    if (fRunRange[0])
1985    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
1986    if (!fRunRange[0] && !fRunNumbers.Length()) {
1987       TIter next(fInputFiles);
1988       TObject *obj;
1989       TString list;
1990       while ((obj=next())) list += obj->GetName();
1991       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1992    }
1993    if (TestBit(AliAnalysisGrid::kTest))
1994    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1995    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1996    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1997    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1998    printf("=   List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
1999    printf("=====================================================================\n");
2000    printf("=   Job price: ___________________________________ %d\n", fPrice);
2001    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
2002    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
2003    if (fMaxInitFailed>0) 
2004    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
2005    if (fMasterResubmitThreshold>0) 
2006    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
2007    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
2008    if (fNrunsPerMaster>0)
2009    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
2010    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
2011    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
2012    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
2013    if (fArguments.Length()) 
2014    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
2015    if (fExecutableArgs.Length()) 
2016    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
2017    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
2018    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
2019    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2020    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
2021    if (fDatasetName)
2022    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
2023    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
2024    if (fIncludePath.Data())
2025    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2026    if (fCloseSE.Length())
2027    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
2028    if (fFriendChainName.Length())
2029    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
2030    if (fPackages && fPackages->GetEntries()) {
2031       TIter next(fPackages);
2032       TObject *obj;
2033       TString list;
2034       while ((obj=next())) list += obj->GetName();
2035       printf("=   Par files to be used: ________________________ %s\n", list.Data());
2036    }   
2037 }
2038
2039 //______________________________________________________________________________
2040 void AliAnalysisAlien::SetDefaults()
2041 {
2042 // Set default values for everything. What cannot be filled will be left empty.
2043    if (fGridJDL) delete fGridJDL;
2044    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2045    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2046    fPrice                      = 1;
2047    fTTL                        = 30000;
2048    fSplitMaxInputFileNumber    = 100;
2049    fMaxInitFailed              = 0;
2050    fMasterResubmitThreshold    = 0;
2051    fNtestFiles                 = 10;
2052    fNreplicas                  = 2;
2053    fRunRange[0]                = 0;
2054    fRunRange[1]                = 0;
2055    fRunPrefix                  = "%d";
2056    fNrunsPerMaster             = 1;
2057    fMaxMergeFiles              = 100;
2058    fRunNumbers                 = "";
2059    fExecutable                 = "analysis.sh";
2060    fExecutableCommand          = "root -b -q";
2061    fArguments                  = "";
2062    fExecutableArgs             = "";
2063    fAnalysisMacro              = "myAnalysis.C";
2064    fAnalysisSource             = "";
2065    fAdditionalLibs             = "";
2066    fSplitMode                  = "se";
2067    fAPIVersion                 = "";
2068    fROOTVersion                = "";
2069    fAliROOTVersion             = "";
2070    fUser                       = "";  // Your alien user name
2071    fGridWorkingDir             = "";
2072    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
2073    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
2074    fFriendChainName            = "";
2075    fGridOutputDir              = "output";
2076    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
2077    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
2078    fInputFormat                = "xml-single";
2079    fJDLName                    = "analysis.jdl";
2080    fJobTag                     = "Automatically generated analysis JDL";
2081    fMergeExcludes              = "";
2082    fMergeViaJDL                = 0;
2083    SetUseCopy(kTRUE);
2084    SetCheckCopy(kTRUE);
2085    SetDefaultOutputs(kTRUE);
2086    fOverwriteMode              = 1;
2087 }   
2088
2089 //______________________________________________________________________________
2090 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
2091 {
2092 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
2093    // First check if the result is already in the output directory.
2094    if (FileExists(Form("%s/%s",aliendir,filename))) {
2095       printf("Final merged results found. Not merging again.\n");
2096       return kFALSE;
2097    }
2098    // Now check the last stage done.
2099    Int_t stage = 0;
2100    while (1) {
2101       if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
2102       stage++;
2103    }
2104    // Next stage of merging
2105    stage++;
2106    TString pattern = "*root_archive.zip";
2107    if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
2108    TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
2109    if (res) delete res;
2110    // Write standard output to file
2111    gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
2112    // Count the number of files inside
2113    ifstream ifile;
2114    ifile.open(Form("Stage_%d.xml",stage));
2115    if (!ifile.good()) {
2116       ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
2117       return kFALSE;
2118    }   
2119    TString line;
2120    Int_t nfiles = 0;
2121    while (!ifile.eof()) {
2122       ifile >> line;
2123       if (line.Contains("/event")) nfiles++;
2124    }
2125    ifile.close();
2126    if (!nfiles) {
2127       ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
2128       return kFALSE;
2129    } else {
2130       printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
2131    }   
2132    // Copy the file in the output directory
2133    printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
2134    TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
2135    if (!copyLocal2Alien("CheckMergedFiles", Form("Stage_%d.xml",stage), 
2136         Form("%s/Stage_%d.xml",aliendir,stage))) Fatal("","Terminating");
2137    // Check if this is the last stage to be done.
2138    Bool_t laststage = (nfiles<nperchunk);
2139    if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
2140    if (laststage) {
2141       printf("### Submiting final merging stage %d\n", stage);
2142       TString finalJDL = jdl;
2143       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2144       TString query = Form("submit %s %s %d", finalJDL.Data(), aliendir, stage);
2145       Int_t jobId = SubmitSingleJob(query);
2146       if (!jobId) return kFALSE;      
2147    } else {
2148       printf("### Submiting merging stage %d\n", stage);
2149       TString query = Form("submit %s %s %d", jdl, aliendir, stage);
2150       Int_t jobId = SubmitSingleJob(query);
2151       if (!jobId) return kFALSE;           
2152    }
2153    return kTRUE;   
2154 }        
2155
2156 //______________________________________________________________________________
2157 AliAnalysisManager *AliAnalysisAlien::LoadAnalysisManager(const char *fname)
2158 {
2159 // Loat the analysis manager from a file.
2160    TFile *file = TFile::Open(fname);
2161    if (!file) {
2162       ::Error("LoadAnalysisManager", "Cannot open file %s", fname);
2163       return 0;
2164    }   
2165    TIter nextkey(file->GetListOfKeys());
2166    AliAnalysisManager *mgr = 0;
2167    TKey *key;
2168    while ((key=(TKey*)nextkey())) {
2169       if (!strcmp(key->GetClassName(), "AliAnalysisManager"))
2170          mgr = (AliAnalysisManager*)file->Get(key->GetName());
2171    }
2172    if (!mgr) 
2173       ::Error("LoadAnalysisManager", "No analysis manager found in file %s", fname);
2174    return mgr;
2175 }      
2176
2177 //______________________________________________________________________________
2178 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
2179 {
2180 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
2181    if (!gGrid) return 0;
2182    printf("=> %s ------> ",query);
2183    TGridResult *res = gGrid->Command(query);
2184    if (!res) return 0;
2185    TString jobId = res->GetKey(0,"jobId");
2186    delete res;
2187    if (jobId.IsNull()) {
2188       printf("submission failed. Reason:\n");
2189       gGrid->Stdout();
2190       gGrid->Stderr();
2191       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
2192       return 0;
2193    }
2194    printf(" Job id: %s\n", jobId.Data());
2195    return atoi(jobId);
2196 }  
2197
2198 //______________________________________________________________________________
2199 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
2200 {
2201 // Merge given output files from basedir. Basedir can be an alien output directory
2202 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
2203 // files in a group (ignored for xml input). Merging can be done in stages:
2204 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
2205 // stage=1 : works with an xml of all root_archive.zip in the output directory
2206 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
2207    TString outputFile = output;
2208    TString command;
2209    TString outputChunk;
2210    TString previousChunk = "";
2211    TObjArray *listoffiles = new TObjArray();
2212 //   listoffiles->SetOwner();
2213    Int_t countChunk = 0;
2214    Int_t countZero = nmaxmerge;
2215    Bool_t merged = kTRUE;
2216    Int_t index = outputFile.Index("@");
2217    if (index > 0) outputFile.Remove(index);
2218    TString inputFile = outputFile;
2219    TString sbasedir = basedir;
2220    if (sbasedir.Contains(".xml")) {
2221       // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
2222       nmaxmerge = 9999999;
2223       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
2224       if (!coll) {
2225          ::Error("MergeOutput", "Input XML collection empty.");
2226          return kFALSE;
2227       }
2228       // Iterate grid collection
2229       while (coll->Next()) {
2230          TString fname = gSystem->DirName(coll->GetTURL());
2231          fname += "/";
2232          fname += inputFile;      
2233          listoffiles->Add(new TNamed(fname.Data(),""));
2234       }   
2235    } else {   
2236       command = Form("find %s/ *%s", basedir, inputFile.Data());
2237       printf("command: %s\n", command.Data());
2238       TGridResult *res = gGrid->Command(command);
2239       if (!res) {
2240          ::Error("MergeOutput","No result for the find command\n");
2241          delete listoffiles;
2242          return kFALSE;
2243       }     
2244       TIter nextmap(res);
2245       TMap *map = 0;
2246       while ((map=(TMap*)nextmap())) {
2247          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
2248          if (!objs || !objs->GetString().Length()) {
2249             // Nothing found - skip this output
2250             delete res;
2251             delete listoffiles;
2252             return kFALSE;
2253          }
2254          listoffiles->Add(new TNamed(objs->GetName(),""));
2255       }
2256       delete res;
2257    }
2258    if (!listoffiles->GetEntries()) {
2259       ::Error("MergeOutput","No result for the find command\n");
2260       delete listoffiles;
2261       return kFALSE;
2262    }     
2263
2264    TFileMerger *fm = 0;
2265    TIter next0(listoffiles);
2266    TObjArray *listoffilestmp = new TObjArray();
2267    listoffilestmp->SetOwner();
2268    TObject *nextfile;
2269    TString snextfile;
2270    // Keep only the files at upper level
2271    Int_t countChar = 0;
2272    while ((nextfile=next0())) {
2273       snextfile = nextfile->GetName();
2274       Int_t crtCount = snextfile.CountChar('/');
2275       if (nextfile == listoffiles->First()) countChar = crtCount;
2276       if (crtCount < countChar) countChar = crtCount;
2277    }
2278    next0.Reset();
2279    while ((nextfile=next0())) {
2280       snextfile = nextfile->GetName();
2281       Int_t crtCount = snextfile.CountChar('/');
2282       if (crtCount > countChar) {
2283          delete nextfile;
2284          continue;
2285       }   
2286       listoffilestmp->Add(nextfile);
2287    }
2288    delete listoffiles;
2289    listoffiles = listoffilestmp;  // Now contains 'good' files
2290    listoffiles->Print();
2291    TIter next(listoffiles);   
2292    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2293    outputChunk = outputFile;
2294    outputChunk.ReplaceAll(".root", "_*.root");
2295    // Check for existent temporary merge files
2296    // Check overwrite mode and remove previous partial results if needed
2297    // Preserve old merging functionality for stage 0.
2298    if (stage==0) {
2299       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2300          while (1) {
2301             // Skip as many input files as in a chunk
2302             for (Int_t counter=0; counter<nmaxmerge; counter++) {
2303                nextfile = next();
2304                if (!nextfile) {
2305                   ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
2306                   delete listoffiles;
2307                   return kFALSE;
2308                }   
2309                snextfile = nextfile->GetName();
2310             }
2311             outputChunk = outputFile;
2312             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2313             countChunk++;
2314             if (gSystem->AccessPathName(outputChunk)) continue;
2315             // Merged file with chunks up to <countChunk> found
2316             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
2317             previousChunk = outputChunk;
2318             break;
2319          }
2320       }   
2321       countZero = nmaxmerge;
2322    
2323       while ((nextfile=next())) {
2324          snextfile = nextfile->GetName();
2325          // Loop 'find' results and get next LFN
2326          if (countZero == nmaxmerge) {
2327             // First file in chunk - create file merger and add previous chunk if any.
2328             fm = new TFileMerger(kFALSE);
2329             fm->SetFastMethod(kTRUE);
2330             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
2331             outputChunk = outputFile;
2332             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2333          }
2334          // If last file found, put merged results in the output file
2335          if (nextfile == listoffiles->Last()) outputChunk = outputFile;
2336          // Add file to be merged and decrement chunk counter.
2337          fm->AddFile(snextfile);
2338          countZero--;
2339          if (countZero==0 || nextfile == listoffiles->Last()) {            
2340             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2341             // Nothing found - skip this output
2342                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2343                merged = kFALSE;
2344                break;
2345             }
2346             fm->OutputFile(outputChunk);
2347             // Merge the outputs, then go to next chunk      
2348             if (!fm->Merge()) {
2349                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2350                merged = kFALSE;
2351                break;
2352             } else {
2353                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
2354                gSystem->Unlink(previousChunk);
2355             }
2356             if (nextfile == listoffiles->Last()) break;
2357             countChunk++;
2358             countZero = nmaxmerge;
2359             previousChunk = outputChunk;
2360          }
2361       }
2362       delete listoffiles;
2363       delete fm;
2364       return merged;
2365    }
2366    // Merging stage different than 0.
2367    // Move to the begining of the requested chunk.
2368    fm = new TFileMerger(kFALSE);
2369    fm->SetFastMethod(kTRUE);
2370    while ((nextfile=next())) fm->AddFile(nextfile->GetName());
2371    delete listoffiles;
2372    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2373       // Nothing found - skip this output
2374       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2375       delete fm;
2376       return kFALSE;
2377    }
2378    fm->OutputFile(outputFile);
2379    // Merge the outputs
2380    if (!fm->Merge()) {
2381       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2382       delete fm;
2383       return kFALSE;
2384    } else {
2385       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
2386    }
2387    delete fm;
2388    return kTRUE;
2389
2390
2391 //______________________________________________________________________________
2392 Bool_t AliAnalysisAlien::MergeOutputs()
2393 {
2394 // Merge analysis outputs existing in the AliEn space.
2395    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
2396    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2397    if (!Connect()) {
2398       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
2399       return kFALSE;
2400    }
2401    if (fMergeViaJDL) {
2402       if (!TestBit(AliAnalysisGrid::kMerge)) {
2403          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
2404          return kFALSE; 
2405       }     
2406       if (fProductionMode) {
2407          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
2408          return kFALSE;
2409       }
2410       Info("MergeOutputs", "Submitting merging JDL");
2411       if (!SubmitMerging()) return kFALSE;
2412       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
2413       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
2414       return kFALSE;
2415    }   
2416    // Get the output path
2417    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2418    if (!DirectoryExists(fGridOutputDir)) {
2419       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
2420       return kFALSE;
2421    }
2422    if (!fOutputFiles.Length()) {
2423       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2424       return kFALSE;
2425    }
2426    // Check if fast read option was requested
2427    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
2428         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
2429    if (fFastReadOption) {
2430       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
2431              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2432       gEnv->SetValue("XNet.ConnectTimeout",50);
2433       gEnv->SetValue("XNet.RequestTimeout",50);
2434       gEnv->SetValue("XNet.MaxRedirectCount",2);
2435       gEnv->SetValue("XNet.ReconnectTimeout",50);
2436       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
2437    }   
2438    // Make sure we change the temporary directory
2439    gSystem->Setenv("TMPDIR", gSystem->pwd());
2440    // Set temporary compilation directory to current one
2441    gSystem->SetBuildDir(gSystem->pwd(), kTRUE);   
2442    TObjArray *list = fOutputFiles.Tokenize(",");
2443    TIter next(list);
2444    TObjString *str;
2445    TString outputFile;
2446    Bool_t merged = kTRUE;
2447    while((str=(TObjString*)next())) {
2448       outputFile = str->GetString();
2449       Int_t index = outputFile.Index("@");
2450       if (index > 0) outputFile.Remove(index);
2451       TString outputChunk = outputFile;
2452       outputChunk.ReplaceAll(".root", "_*.root");
2453       // Skip already merged outputs
2454       if (!gSystem->AccessPathName(outputFile)) {
2455          if (fOverwriteMode) {
2456             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
2457             gSystem->Unlink(outputFile);
2458             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2459                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2460                      outputChunk.Data());
2461                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2462             }
2463          } else {   
2464             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
2465             continue;
2466          }   
2467       } else {
2468          if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2469             Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2470                   outputChunk.Data());
2471             gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2472          }   
2473       }
2474       if (fMergeExcludes.Length() &&
2475           fMergeExcludes.Contains(outputFile.Data())) continue;
2476       // Perform a 'find' command in the output directory, looking for registered outputs    
2477       merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
2478       if (!merged) {
2479          Error("MergeOutputs", "Terminate() will  NOT be executed");
2480          return kFALSE;
2481       }
2482       TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2483       if (fileOpened) fileOpened->Close();
2484    } 
2485    return kTRUE;
2486 }   
2487
2488 //______________________________________________________________________________
2489 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2490 {
2491 // Use the output files connected to output containers from the analysis manager
2492 // rather than the files defined by SetOutputFiles
2493    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
2494       Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
2495    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2496 }
2497       
2498 //______________________________________________________________________________
2499 void AliAnalysisAlien::SetOutputFiles(const char *list)
2500 {
2501 // Manually set the output files list.
2502 // Removes duplicates. Not allowed if default outputs are not disabled.
2503    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2504       Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2505       return;
2506    }
2507    Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2508    fOutputFiles = "";
2509    TString slist = list;
2510    if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2511    TObjArray *arr = slist.Tokenize(" "); 
2512    TObjString *os;
2513    TIter next(arr);
2514    TString sout;
2515    while ((os=(TObjString*)next())) {
2516       sout = os->GetString();
2517       if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2518       if (fOutputFiles.Contains(sout)) continue;
2519       if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2520       fOutputFiles += sout;
2521    }
2522    delete arr;   
2523 }
2524
2525 //______________________________________________________________________________
2526 void AliAnalysisAlien::SetOutputArchive(const char *list)
2527 {
2528 // Manually set the output archive list. Free text - you are on your own...
2529 // Not allowed if default outputs are not disabled.
2530    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2531       Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2532       return;
2533    }
2534    Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2535    fOutputArchive = list;
2536 }
2537
2538 //______________________________________________________________________________
2539 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2540 {
2541 // Setting a prefered output SE is not allowed anymore.
2542    Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2543 }
2544
2545 //______________________________________________________________________________
2546 void AliAnalysisAlien::SetProofParameter(const char *pname, const char *value)
2547 {
2548 // Set some PROOF special parameter.
2549    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
2550    if (pair) {
2551       TObject *old = pair->Key();
2552       TObject *val = pair->Value();
2553       fProofParam.Remove(old);
2554       delete old;
2555       delete val;
2556    }
2557    fProofParam.Add(new TObjString(pname), new TObjString(value));
2558 }
2559
2560 //______________________________________________________________________________
2561 const char *AliAnalysisAlien::GetProofParameter(const char *pname) const
2562 {
2563 // Returns a special PROOF parameter.
2564    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
2565    if (!pair) return 0;
2566    return pair->Value()->GetName();
2567 }      
2568
2569 //______________________________________________________________________________
2570 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
2571 {
2572 // Start remote grid analysis.
2573    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2574    Bool_t testMode = TestBit(AliAnalysisGrid::kTest);
2575    if (!mgr || !mgr->IsInitialized()) {
2576       Error("StartAnalysis", "You need an initialized analysis manager for this");
2577       return kFALSE;
2578    }
2579    // Are we in PROOF mode ?
2580    if (mgr->IsProofMode()) {
2581       if (testMode) Info("StartAnalysis", "##### Starting PROOF analysis with Proof Lite via the plugin #####");
2582       else Info("StartAnalysis", "##### Starting PROOF analysis on cluster <%s> via the plugin #####", fProofCluster.Data());
2583       if (fProofCluster.IsNull()) {
2584          Error("StartAnalysis", "You need to specify the proof cluster name via SetProofCluster");
2585          return kFALSE;
2586       }   
2587       if (fProofDataSet.IsNull() && !testMode) {
2588          Error("StartAnalysis", "You need to specify a dataset using SetProofDataSet()");
2589          return kFALSE;
2590       }   
2591       // Set the needed environment
2592       gEnv->SetValue("XSec.GSI.DelegProxy","2");
2593       // Do we need to reset PROOF ? The success of the Reset operation cannot be checked
2594       if (fProofReset && !testMode) {
2595          if (fProofReset==1) {
2596             Info("StartAnalysis", "Sending soft reset signal to proof cluster %s", fProofCluster.Data());
2597             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kFALSE);", fProofCluster.Data()));
2598          } else {         
2599             Info("StartAnalysis", "Sending hard reset signal to proof cluster %s", fProofCluster.Data());
2600             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kTRUE);", fProofCluster.Data()));
2601          }
2602          Info("StartAnalysis", "Stopping the analysis. Please use SetProofReset(0) to resume.");
2603          return kFALSE;
2604       }
2605       
2606       if (!testMode) {
2607         // Check if there is an old active session
2608         Long_t nsessions = gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->QuerySessions(\"\")->GetEntries();", fProofCluster.Data()));
2609         if (nsessions) {
2610           Error("StartAnalysis","You have to reset your old session first\n");
2611           return kFALSE;
2612         }
2613       }
2614       // Do we need to change the ROOT version ? The success of this cannot be checked.
2615       if (!fRootVersionForProof.IsNull() && !testMode) {
2616          gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"%s\");", 
2617                             fProofCluster.Data(), fRootVersionForProof.Data()));
2618       }
2619       // Connect to PROOF and check the status
2620       Long_t proof = 0;
2621       TString sworkers;
2622       if (fNproofWorkersPerSlave) sworkers = Form("workers=%dx", fNproofWorkersPerSlave);
2623       else if (fNproofWorkers) sworkers = Form("workers=%d", fNproofWorkers);
2624       if (!testMode) {
2625          if (!sworkers.IsNull()) 
2626             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"%s\");", fProofCluster.Data(), sworkers.Data()));
2627          else   
2628             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
2629       } else {
2630          proof = gROOT->ProcessLine("TProof::Open(\"\");");
2631          if (!proof) {
2632             Error("StartAnalysis", "Could not start PROOF in test mode");
2633             return kFALSE;
2634          }   
2635       }
2636       if (!proof) {
2637          Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
2638          return kFALSE;
2639       }   
2640       if (fNproofWorkersPerSlave*fNproofWorkers > 0)
2641          gROOT->ProcessLine(Form("gProof->SetParallel(%d);", fNproofWorkers));
2642       // Set proof special parameters if any
2643       TIter nextpp(&fProofParam);
2644       TObject *proofparam;
2645       while ((proofparam=nextpp())) {
2646          TString svalue = GetProofParameter(proofparam->GetName());
2647          gROOT->ProcessLine(Form("gProof->SetParameter(\"%s\",%s);", proofparam->GetName(), svalue.Data()));
2648       }   
2649       // Is dataset existing ?
2650       if (!testMode) {
2651          TString dataset = fProofDataSet;
2652          Int_t index = dataset.Index("#");
2653          if (index>=0) dataset.Remove(index);
2654 //         if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
2655 //            Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
2656 //            return kFALSE;
2657 //         }
2658 //         Info("StartAnalysis", "Dataset %s found", dataset.Data());
2659       }
2660       // Is ClearPackages() needed ?
2661       if (TestSpecialBit(kClearPackages)) {
2662          Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
2663          gROOT->ProcessLine("gProof->ClearPackages();");
2664       }
2665       // Is a given aliroot mode requested ?
2666       TList optionsList;
2667       TString parLibs;
2668       if (!fAliRootMode.IsNull()) {
2669          TString alirootMode = fAliRootMode;
2670          if (alirootMode == "default") alirootMode = "";
2671          Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
2672          optionsList.SetOwner();
2673          optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
2674          // Check the additional libs to be loaded
2675          TString extraLibs;
2676          Bool_t parMode = kFALSE;
2677          if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:OADB:ANALYSISalice";
2678          // Parse the extra libs for .so
2679          if (fAdditionalLibs.Length()) {
2680             TObjArray *list = fAdditionalLibs.Tokenize(" ");
2681             TIter next(list);
2682             TObjString *str;
2683             while((str=(TObjString*)next())) {
2684                if (str->GetString().Contains(".so")) {
2685                   if (parMode) {
2686                      Warning("StartAnalysis", "Plugin does not support loading libs after par files in PROOF mode. Library %s and following will not load on workers", str->GetName());
2687                      break;
2688                   }   
2689                   TString stmp = str->GetName();
2690                   if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
2691                   stmp.ReplaceAll(".so","");
2692                   if (!extraLibs.IsNull()) extraLibs += ":";
2693                   extraLibs += stmp;
2694                   continue;
2695                }
2696                if (str->GetString().Contains(".par")) {
2697                   // The first par file found in the list will not allow any further .so
2698                   parMode = kTRUE;
2699                   if (!parLibs.IsNull()) parLibs += ":";
2700                   parLibs += str->GetName();
2701                   continue;
2702                }   
2703             }
2704             if (list) delete list;            
2705          }
2706         if (!extraLibs.IsNull()) {
2707           Info("StartAnalysis", "Adding extra libs: %s",extraLibs.Data());
2708           optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
2709         }
2710          // Check extra includes
2711          if (!fIncludePath.IsNull()) {
2712             TString includePath = fIncludePath;
2713             includePath.ReplaceAll(" ",":");
2714             includePath.ReplaceAll("$ALICE_ROOT/","");
2715             includePath.ReplaceAll("${ALICE_ROOT}/","");
2716             includePath.ReplaceAll("-I","");
2717             includePath.Remove(TString::kTrailing, ':');
2718             Info("StartAnalysis", "Adding extra includes: %s",includePath.Data()); 
2719             optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
2720          }
2721          // Check if connection to grid is requested
2722          if (TestSpecialBit(kProofConnectGrid)) 
2723             optionsList.Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
2724          // Enable AliRoot par
2725          if (testMode) {
2726          // Enable proof lite package
2727             TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
2728             for (Int_t i=0; i<optionsList.GetSize(); i++) {
2729                TNamed *obj = (TNamed*)optionsList.At(i);
2730                printf("%s  %s\n", obj->GetName(), obj->GetTitle());
2731             }   
2732             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
2733               && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)%p);",alirootLite.Data(),&optionsList))) {
2734                   Info("StartAnalysis", "AliRootProofLite enabled");
2735             } else {                      
2736                Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
2737                return kFALSE;
2738             }   
2739          } else {
2740            if ( ! fAliROOTVersion.IsNull() ) {
2741              if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)%p, kTRUE);", 
2742                                          fAliROOTVersion.Data(), &optionsList))) {
2743                 Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
2744                 return kFALSE;
2745              }
2746            }
2747          }
2748          // Enable first par files from fAdditionalLibs
2749          if (!parLibs.IsNull()) {
2750             TObjArray *list = parLibs.Tokenize(":");
2751             TIter next(list);
2752             TObjString *package;
2753             while((package=(TObjString*)next())) {
2754                TString spkg = package->GetName();
2755                spkg.ReplaceAll(".par", "");
2756                gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2757                if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2758                   TString enablePackage = (testMode)?Form("gProof->EnablePackage(\"%s\",kFALSE);", package->GetName()):Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName());
2759                   if (gROOT->ProcessLine(enablePackage)) {
2760                      Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2761                      return kFALSE;
2762                   }
2763                } else {
2764                   Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2765                   return kFALSE;
2766                }
2767             }
2768             if (list) delete list; 
2769          }
2770       } else {
2771          if (fAdditionalLibs.Contains(".so") && !testMode) {
2772             Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
2773                    \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
2774             return kFALSE;       
2775          }
2776       }
2777       // Enable par files if requested
2778       if (fPackages && fPackages->GetEntries()) {
2779          TIter next(fPackages);
2780          TObject *package;
2781          while ((package=next())) {
2782             // Skip packages already enabled
2783             if (parLibs.Contains(package->GetName())) continue;
2784             TString spkg = package->GetName();
2785             spkg.ReplaceAll(".par", "");
2786             gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2787             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2788                if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName()))) {
2789                   Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2790                   return kFALSE;
2791                }
2792             } else {
2793                Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2794                return kFALSE;
2795             }
2796          }
2797       }
2798       // Do we need to load analysis source files ?
2799       // NOTE: don't load on client since this is anyway done by the user to attach his task.
2800       if (fAnalysisSource.Length()) {
2801          TObjArray *list = fAnalysisSource.Tokenize(" ");
2802          TIter next(list);
2803          TObjString *str;
2804          while((str=(TObjString*)next())) {
2805             gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
2806          }
2807          if (list) delete list;
2808       }
2809       if (testMode) {
2810       // Register dataset to proof lite.
2811          if (fFileForTestMode.IsNull()) {
2812             Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2813             return kFALSE;
2814          }
2815          if (gSystem->AccessPathName(fFileForTestMode)) {
2816             Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2817             return kFALSE;
2818          }   
2819          TFileCollection *coll = new TFileCollection();
2820          coll->AddFromFile(fFileForTestMode);
2821          gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)%p, \"OV\");", coll));
2822          gROOT->ProcessLine("gProof->ShowDataSets()");
2823       }
2824       return kTRUE;
2825    }
2826    
2827    // Check if output files have to be taken from the analysis manager
2828    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2829       // Add output files and AOD files
2830       fOutputFiles = GetListOfFiles("outaod");
2831       // Add extra files registered to the analysis manager
2832       TString extra = GetListOfFiles("ext");
2833       if (!extra.IsNull()) {
2834          extra.ReplaceAll(".root", "*.root");
2835          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2836          fOutputFiles += extra;
2837       }
2838       // Compose the output archive.
2839       fOutputArchive = "log_archive.zip:std*@disk=1 ";
2840       fOutputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",fOutputFiles.Data(),fNreplicas);
2841    }
2842 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
2843    if (TestBit(AliAnalysisGrid::kOffline)) {
2844       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2845       \n                         there nor any job run. You can revise the JDL and analysis \
2846       \n                         macro then run the same in \"submit\" mode.");
2847    } else if (TestBit(AliAnalysisGrid::kTest)) {
2848       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
2849       \n                         dataset.");
2850    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2851       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
2852       \n                         space and job submitted.");
2853    } else if (TestBit(AliAnalysisGrid::kMerge)) {
2854       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
2855       if (fMergeViaJDL) CheckInputData();
2856       return kTRUE;
2857    } else {
2858       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
2859    }   
2860       
2861    Print();   
2862    if (!Connect()) {
2863       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
2864       return kFALSE;
2865    }
2866    if (IsCheckCopy() && gGrid) CheckFileCopy(gGrid->GetHomeDirectory());
2867    if (!CheckInputData()) {
2868       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
2869       return kFALSE;
2870    }   
2871    if (!CreateDataset(fDataPattern)) {
2872       TString serror;
2873       if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2874       if (fRunNumbers.Length()) serror = "run numbers";
2875       if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2876       serror += Form("\n   or data pattern <%s>", fDataPattern.Data());
2877       Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2878       return kFALSE;
2879    }   
2880    WriteAnalysisFile();   
2881    WriteAnalysisMacro();
2882    WriteExecutable();
2883    WriteValidationScript();
2884    if (fMergeViaJDL) {
2885       WriteMergingMacro();
2886       WriteMergeExecutable();
2887       WriteValidationScript(kTRUE);
2888    }   
2889    if (!CreateJDL()) return kFALSE;
2890    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2891    if (testMode) {
2892       // Locally testing the analysis
2893       Info("StartAnalysis", "\n_______________________________________________________________________ \
2894       \n   Running analysis script in a daughter shell as on a worker node \
2895       \n_______________________________________________________________________");
2896       TObjArray *list = fOutputFiles.Tokenize(",");
2897       TIter next(list);
2898       TObjString *str;
2899       TString outputFile;
2900       while((str=(TObjString*)next())) {
2901          outputFile = str->GetString();
2902          Int_t index = outputFile.Index("@");
2903          if (index > 0) outputFile.Remove(index);         
2904          if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
2905       }
2906       delete list;
2907       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
2908       gSystem->Exec(Form("bash %s",fValidationScript.Data()));
2909 //      gSystem->Exec("cat stdout");
2910       return kFALSE;
2911    }
2912    // Check if submitting is managed by LPM manager
2913    if (fProductionMode) {
2914       TString prodfile = fJDLName;
2915       prodfile.ReplaceAll(".jdl", ".prod");
2916       WriteProductionFile(prodfile);
2917       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2918       return kFALSE;
2919    }   
2920    // Submit AliEn job(s)
2921    gGrid->Cd(fGridOutputDir);
2922    TGridResult *res;
2923    TString jobID = "";
2924    if (!fRunNumbers.Length() && !fRunRange[0]) {
2925       // Submit a given xml or a set of runs
2926       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
2927       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
2928       if (res) {
2929          const char *cjobId = res->GetKey(0,"jobId");
2930          if (!cjobId) {
2931             gGrid->Stdout();
2932             gGrid->Stderr();
2933             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
2934             return kFALSE;
2935          } else {
2936             Info("StartAnalysis", "\n_______________________________________________________________________ \
2937             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2938             \n_______________________________________________________________________",
2939                    fJDLName.Data(), cjobId);
2940             jobID = cjobId;      
2941          }          
2942          delete res;
2943       } else {
2944          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2945          return kFALSE;      
2946       }   
2947    } else {
2948       // Submit for a range of enumeration of runs.
2949       if (!Submit()) return kFALSE;
2950    }   
2951          
2952    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2953    \n You may exit at any time and terminate the job later using the option <terminate> \
2954    \n ##################################################################################", jobID.Data());
2955    gSystem->Exec("aliensh");
2956    return kTRUE;
2957 }
2958
2959 //______________________________________________________________________________
2960 const char *AliAnalysisAlien::GetListOfFiles(const char *type)
2961 {
2962 // Get a comma-separated list of output files of the requested type.
2963 // Type can be (case unsensitive):
2964 //    aod - list of aod files (std, extensions and filters)
2965 //    out - list of output files connected to containers (but not aod's or extras)
2966 //    ext - list of extra files registered to the manager
2967 //    ter - list of files produced in terminate
2968    static TString files;
2969    files = "";
2970    TString stype = type;
2971    stype.ToLower();
2972    TString aodfiles, extra;
2973    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2974    if (!mgr) {
2975       ::Error("GetListOfFiles", "Cannot call this without analysis manager");
2976       return files.Data();
2977    }
2978    if (mgr->GetOutputEventHandler()) {
2979       aodfiles = mgr->GetOutputEventHandler()->GetOutputFileName();
2980       TString extraaod = mgr->GetOutputEventHandler()->GetExtraOutputs();
2981       if (!extraaod.IsNull()) {
2982          aodfiles += ",";
2983          aodfiles += extraaod;
2984       }
2985    }
2986    if (stype.Contains("aod")) {
2987       files = aodfiles;
2988       if (stype == "aod") return files.Data();
2989    }  
2990    // Add output files that are not in the list of AOD files 
2991    TString outputfiles = "";
2992    TIter next(mgr->GetOutputs());
2993    AliAnalysisDataContainer *output;
2994    const char *filename = 0;
2995    while ((output=(AliAnalysisDataContainer*)next())) {
2996       filename = output->GetFileName();
2997       if (!(strcmp(filename, "default"))) continue;
2998       if (outputfiles.Contains(filename)) continue;
2999       if (aodfiles.Contains(filename))    continue;
3000       if (!outputfiles.IsNull()) outputfiles += ",";
3001       outputfiles += filename;
3002    }
3003    if (stype.Contains("out")) {
3004       if (!files.IsNull()) files += ",";
3005       files += outputfiles;
3006       if (stype == "out") return files.Data();
3007    }   
3008    // Add extra files registered to the analysis manager
3009    TString sextra;
3010    extra = mgr->GetExtraFiles();
3011    if (!extra.IsNull()) {
3012       extra.Strip();
3013       extra.ReplaceAll(" ", ",");
3014       TObjArray *fextra = extra.Tokenize(",");
3015       TIter nextx(fextra);
3016       TObject *obj;
3017       while ((obj=nextx())) {
3018          if (aodfiles.Contains(obj->GetName())) continue;
3019          if (outputfiles.Contains(obj->GetName())) continue;
3020          if (sextra.Contains(obj->GetName())) continue;
3021          if (!sextra.IsNull()) sextra += ",";
3022          sextra += obj->GetName();
3023       }
3024       delete fextra;
3025       if (stype.Contains("ext")) {
3026          if (!files.IsNull()) files += ",";
3027          files += sextra;
3028       }
3029    }   
3030    if (stype == "ext") return files.Data();
3031    TString termfiles;
3032    if (!fTerminateFiles.IsNull()) {
3033       fTerminateFiles.Strip();
3034       fTerminateFiles.ReplaceAll(" ",",");
3035       TObjArray *fextra = fTerminateFiles.Tokenize(",");
3036       TIter nextx(fextra);
3037       TObject *obj;
3038       while ((obj=nextx())) {
3039          if (aodfiles.Contains(obj->GetName())) continue;
3040          if (outputfiles.Contains(obj->GetName())) continue;
3041          if (termfiles.Contains(obj->GetName())) continue;
3042          if (sextra.Contains(obj->GetName())) continue;
3043          if (!termfiles.IsNull()) termfiles += ",";
3044          termfiles += obj->GetName();
3045       }
3046       delete fextra;
3047    }   
3048    if (stype.Contains("ter")) {
3049       if (!files.IsNull() && !termfiles.IsNull()) {
3050          files += ",";
3051          files += termfiles;
3052       }   
3053    }   
3054    return files.Data();
3055 }   
3056
3057 //______________________________________________________________________________
3058 Bool_t AliAnalysisAlien::Submit()
3059 {
3060 // Submit all master jobs.
3061    Int_t nmasterjobs = fInputFiles->GetEntries();
3062    Long_t tshoot = gSystem->Now();
3063    if (!fNsubmitted && !SubmitNext()) return kFALSE;
3064    while (fNsubmitted < nmasterjobs) {
3065       Long_t now = gSystem->Now();
3066       if ((now-tshoot)>30000) {
3067          tshoot = now;
3068          if (!SubmitNext()) return kFALSE;
3069       }   
3070    }
3071    return kTRUE;
3072 }
3073
3074 //______________________________________________________________________________
3075 Bool_t AliAnalysisAlien::SubmitMerging()
3076 {
3077 // Submit all merging jobs.
3078    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3079    gGrid->Cd(fGridOutputDir);
3080    TString mergeJDLName = fExecutable;
3081    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
3082    if (!fInputFiles) {
3083       Error("SubmitMerging", "You have to use explicit run numbers or run range to merge via JDL!");
3084       return kFALSE;
3085    }   
3086    Int_t ntosubmit = fInputFiles->GetEntries();
3087    for (Int_t i=0; i<ntosubmit; i++) {
3088       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3089       runOutDir.ReplaceAll(".xml", "");
3090       if (fOutputToRunNo) {
3091          // The output directory is the run number
3092          printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
3093          runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
3094       } else {
3095          if (!fRunNumbers.Length() && !fRunRange[0]) {
3096             // The output directory is the grid outdir
3097             printf("### Submitting merging job for the full output directory %s.\n", fGridOutputDir.Data());
3098             runOutDir = fGridOutputDir;
3099          } else {
3100             // The output directory is the master number in 3 digits format
3101             printf("### Submitting merging job for master <%03d>\n", i);
3102             runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
3103          }   
3104       }
3105       // Check now the number of merging stages.
3106       TObjArray *list = fOutputFiles.Tokenize(",");
3107       TIter next(list);
3108       TObjString *str;
3109       TString outputFile;
3110       while((str=(TObjString*)next())) {
3111          outputFile = str->GetString();
3112          Int_t index = outputFile.Index("@");
3113          if (index > 0) outputFile.Remove(index);
3114          if (!fMergeExcludes.Contains(outputFile)) break;
3115       }
3116       delete list;
3117       Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, mergeJDLName);
3118       if (!done && (i==ntosubmit-1)) return kFALSE;
3119       if (!fRunNumbers.Length() && !fRunRange[0]) break;
3120    }
3121    if (!ntosubmit) return kTRUE;
3122    Info("StartAnalysis", "\n #### STARTING AN ALIEN SHELL FOR YOU. You can exit any time or inspect your jobs in a different shell.##########\
3123                           \n Make sure your jobs are in a final state (you can resubmit failed ones via 'masterjob <id> resubmit ERROR_ALL')\
3124                           \n Rerun in 'terminate' mode to submit all merging stages, each AFTER the previous one completed. The final merged \
3125                           \n output will be written to your alien output directory, while separate stages in <Stage_n>. \
3126                           \n ################################################################################################################");
3127    gSystem->Exec("aliensh");
3128    return kTRUE;
3129 }
3130
3131 //______________________________________________________________________________
3132 Bool_t AliAnalysisAlien::SubmitNext()
3133 {
3134 // Submit next bunch of master jobs if the queue is free. The first master job is
3135 // submitted right away, while the next will not be unless the previous was split.
3136 // The plugin will not submit new master jobs if there are more that 500 jobs in
3137 // waiting phase.
3138    static Bool_t iscalled = kFALSE;
3139    static Int_t firstmaster = 0;
3140    static Int_t lastmaster = 0;
3141    static Int_t npermaster  = 0;
3142    if (iscalled) return kTRUE;
3143    iscalled = kTRUE;
3144    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
3145    Int_t ntosubmit = 0;
3146    TGridResult *res;
3147    TString jobID = "";
3148    Int_t nmasterjobs = fInputFiles->GetEntries();
3149    if (!fNsubmitted) {
3150       ntosubmit = 1;
3151       if (!IsUseSubmitPolicy()) {
3152          if (nmasterjobs>5)
3153             Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
3154                 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
3155          ntosubmit = nmasterjobs;
3156       }   
3157    } else {
3158       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
3159       printf("=== master %d: %s\n", lastmaster, status.Data());
3160       // If last master not split, just return
3161       if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
3162       // No more than 100 waiting jobs
3163       if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
3164       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
3165       if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
3166       if (!ntosubmit) ntosubmit = 1;
3167       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
3168              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
3169    }
3170    for (Int_t i=0; i<ntosubmit; i++) {
3171       // Submit for a range of enumeration of runs.
3172       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
3173       TString query;
3174       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
3175       runOutDir.ReplaceAll(".xml", "");
3176       if (fOutputToRunNo)
3177          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
3178       else
3179          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
3180       printf("********* %s\n",query.Data());
3181       res = gGrid->Command(query);
3182       if (res) {
3183          TString cjobId1 = res->GetKey(0,"jobId");
3184          if (!cjobId1.Length()) {
3185             iscalled = kFALSE;
3186             gGrid->Stdout();
3187             gGrid->Stderr();
3188             Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
3189             return kFALSE;
3190          } else {
3191             Info("StartAnalysis", "\n_______________________________________________________________________ \
3192             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
3193             \n_______________________________________________________________________",
3194                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
3195             jobID += cjobId1;
3196             jobID += " ";
3197             lastmaster = cjobId1.Atoi();
3198             if (!firstmaster) firstmaster = lastmaster;
3199             fNsubmitted++;
3200          }          
3201          delete res;
3202       } else {
3203          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
3204          return kFALSE;
3205       }   
3206    }
3207    iscalled = kFALSE;
3208    return kTRUE;
3209 }
3210
3211 //______________________________________________________________________________
3212 void AliAnalysisAlien::WriteAnalysisFile()
3213 {
3214 // Write current analysis manager into the file <analysisFile>
3215    TString analysisFile = fExecutable;
3216    analysisFile.ReplaceAll(".sh", ".root");
3217    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3218       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3219       if (!mgr || !mgr->IsInitialized()) {
3220          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
3221          return;
3222       }
3223       // Check analysis type
3224       TObject *handler;
3225       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
3226       handler = (TObject*)mgr->GetInputEventHandler();
3227       if (handler) {
3228          if (handler->InheritsFrom("AliMultiInputEventHandler")) {
3229             AliMultiInputEventHandler *multiIH = (AliMultiInputEventHandler*)handler;
3230             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3231             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
3232          } else {
3233             if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3234             if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
3235          }
3236       }
3237       TDirectory *cdir = gDirectory;
3238       TFile *file = TFile::Open(analysisFile, "RECREATE");
3239       if (file) {
3240          // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
3241          if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
3242          // Unless merging makes no sense
3243          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
3244          mgr->Write();
3245          delete file;
3246          // Enable termination for local jobs
3247          mgr->SetSkipTerminate(kFALSE);
3248       }
3249       if (cdir) cdir->cd();
3250       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
3251    }   
3252    Bool_t copy = kTRUE;
3253    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3254    if (copy) {
3255       CdWork();
3256       TString workdir = gGrid->GetHomeDirectory();
3257       workdir += fGridWorkingDir;
3258       Info("WriteAnalysisFile", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
3259       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
3260       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
3261       if (!copyLocal2Alien("WriteAnalysisFile",analysisFile.Data(), 
3262           Form("%s/%s", workdir.Data(),analysisFile.Data()))) Fatal("","Terminating");
3263    }   
3264 }
3265
3266 //______________________________________________________________________________
3267 void AliAnalysisAlien::WriteAnalysisMacro()
3268 {
3269 // Write the analysis macro that will steer the analysis in grid mode.
3270    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3271       ofstream out;
3272       out.open(fAnalysisMacro.Data(), ios::out);
3273       if (!out.good()) {
3274          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3275          return;
3276       }
3277       Bool_t hasSTEERBase = kFALSE;
3278       Bool_t hasESD = kFALSE;
3279       Bool_t hasAOD = kFALSE;
3280       Bool_t hasANALYSIS = kFALSE;
3281       Bool_t hasOADB = kFALSE;
3282       Bool_t hasANALYSISalice = kFALSE;
3283       Bool_t hasCORRFW = kFALSE;
3284       TString func = fAnalysisMacro;
3285       TString type = "ESD";
3286       TString comment = "// Analysis using ";
3287       if (IsUseMCchain()) {
3288          type = "MC";
3289          comment += "MC";
3290       } else {   
3291          if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
3292          if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
3293             type = "AOD";
3294             comment += "AOD";
3295          }   
3296       }
3297       if (type!="AOD" && fFriendChainName!="") {
3298          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
3299          return;
3300       }
3301       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
3302       else comment += " data";
3303       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
3304       func.ReplaceAll(".C", "");
3305       out << "void " << func.Data() << "()" << endl; 
3306       out << "{" << endl;
3307       out << comment.Data() << endl;
3308       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
3309       out << "   TStopwatch timer;" << endl;
3310       out << "   timer.Start();" << endl << endl;
3311       // Change temp directory to current one
3312       out << "// Set temporary merging directory to current one" << endl;
3313       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
3314       out << "// Set temporary compilation directory to current one" << endl;
3315       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
3316       // Reset existing include path
3317       out << "// Reset existing include path and add current directory first in the search" << endl;
3318       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
3319       if (!fExecutableCommand.Contains("aliroot")) {
3320          out << "// load base root libraries" << endl;
3321          out << "   gSystem->Load(\"libTree\");" << endl;
3322          out << "   gSystem->Load(\"libGeom\");" << endl;
3323          out << "   gSystem->Load(\"libVMC\");" << endl;
3324          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
3325          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
3326       }   
3327       if (fAdditionalRootLibs.Length()) {
3328          // in principle libtree /lib geom libvmc etc. can go into this list, too
3329          out << "// Add aditional libraries" << endl;
3330          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3331          TIter next(list);
3332          TObjString *str;
3333          while((str=(TObjString*)next())) {
3334             if (str->GetString().Contains(".so"))
3335             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3336          }
3337          if (list) delete list;
3338       }
3339       out << "// Load analysis framework libraries" << endl;
3340       TString setupPar = "AliAnalysisAlien::SetupPar";
3341       if (!fPackages) {
3342          if (!fExecutableCommand.Contains("aliroot")) {         
3343             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3344             out << "   gSystem->Load(\"libESD\");" << endl;
3345             out << "   gSystem->Load(\"libAOD\");" << endl;
3346          }   
3347          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3348          out << "   gSystem->Load(\"libOADB\");" << endl;
3349          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3350          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3351       } else {
3352          TIter next(fPackages);
3353          TObject *obj;
3354          TString pkgname;
3355          while ((obj=next())) {
3356             pkgname = obj->GetName();
3357             if (pkgname == "STEERBase" ||
3358                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3359             if (pkgname == "ESD" ||
3360                 pkgname == "ESD.par")       hasESD = kTRUE;
3361             if (pkgname == "AOD" ||
3362                 pkgname == "AOD.par")       hasAOD = kTRUE;
3363             if (pkgname == "ANALYSIS" ||
3364                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
3365             if (pkgname == "OADB" ||
3366                 pkgname == "OADB.par")      hasOADB = kTRUE;
3367             if (pkgname == "ANALYSISalice" ||
3368                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3369             if (pkgname == "CORRFW" ||
3370                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
3371          }
3372          if (hasANALYSISalice) setupPar = "SetupPar";   
3373          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3374          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3375          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
3376          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
3377          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
3378          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
3379          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3380          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3381          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
3382          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
3383          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3384          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3385          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3386          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3387          out << "// Compile other par packages" << endl;
3388          next.Reset();
3389          while ((obj=next())) {
3390             pkgname = obj->GetName();
3391             if (pkgname == "STEERBase" ||
3392                 pkgname == "STEERBase.par" ||
3393                 pkgname == "ESD" ||
3394                 pkgname == "ESD.par" ||
3395                 pkgname == "AOD" ||
3396                 pkgname == "AOD.par" ||
3397                 pkgname == "ANALYSIS" ||
3398                 pkgname == "ANALYSIS.par" ||
3399                 pkgname == "OADB" ||
3400                 pkgname == "OADB.par" ||
3401                 pkgname == "ANALYSISalice" ||
3402                 pkgname == "ANALYSISalice.par" ||
3403                 pkgname == "CORRFW" ||
3404                 pkgname == "CORRFW.par") continue;
3405             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3406          }   
3407       }   
3408       out << "// include path" << endl;
3409       // Get the include path from the interpreter and remove entries pointing to AliRoot
3410       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
3411       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3412       out << "   TIter nextpath(listpaths);" << endl;
3413       out << "   TObjString *pname;" << endl;
3414       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
3415       out << "      TString current = pname->GetName();" << endl;
3416       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3417       out << "      gSystem->AddIncludePath(current);" << endl;
3418       out << "   }" << endl;
3419       out << "   if (listpaths) delete listpaths;" << endl;
3420       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3421       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3422       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3423       if (fAdditionalLibs.Length()) {
3424          out << "// Add aditional AliRoot libraries" << endl;
3425          TObjArray *list = fAdditionalLibs.Tokenize(" ");
3426          TIter next(list);
3427          TObjString *str;
3428          while((str=(TObjString*)next())) {
3429             if (str->GetString().Contains(".so"))
3430                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3431             if (str->GetString().Contains(".par"))
3432                out << "   if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
3433          }
3434          if (list) delete list;
3435       }
3436       out << endl;
3437       out << "// analysis source to be compiled at runtime (if any)" << endl;
3438       if (fAnalysisSource.Length()) {
3439          TObjArray *list = fAnalysisSource.Tokenize(" ");
3440          TIter next(list);
3441          TObjString *str;
3442          while((str=(TObjString*)next())) {
3443             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3444          }   
3445          if (list) delete list;
3446       }
3447       out << endl;
3448 //      out << "   printf(\"Currently load libraries:\\n\");" << endl;
3449 //      out << "   printf(\"%s\\n\", gSystem->GetLibraries());" << endl;
3450       if (fFastReadOption) {
3451          Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. This may skip some files that could be accessed !!! \
3452                 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3453          out << "// fast xrootd reading enabled" << endl;
3454          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3455          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3456          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3457          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3458          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3459          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3460       }   
3461       out << "// connect to AliEn and make the chain" << endl;
3462       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
3463       out << "// read the analysis manager from file" << endl;
3464       TString analysisFile = fExecutable;
3465       analysisFile.ReplaceAll(".sh", ".root");
3466       out << "   AliAnalysisManager *mgr = AliAnalysisAlien::LoadAnalysisManager(\"" 
3467           << analysisFile << "\");" << endl;
3468       out << "   if (!mgr) return;" << endl;
3469       out << "   mgr->PrintStatus();" << endl;
3470       if (AliAnalysisManager::GetAnalysisManager()) {
3471          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3472             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3473          } else {
3474             if (TestBit(AliAnalysisGrid::kTest))            
3475                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3476             else
3477                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3478          }
3479       }   
3480       if (IsUsingTags()) {
3481          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
3482       } else {
3483          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;   
3484       }   
3485       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
3486       out << "   timer.Stop();" << endl;
3487       out << "   timer.Print();" << endl;
3488       out << "}" << endl << endl;
3489       if (IsUsingTags()) {
3490          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
3491          out << "{" << endl;
3492          out << "// Create a chain using tags from the xml file." << endl;
3493          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
3494          out << "   if (!coll) {" << endl;
3495          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3496          out << "      return NULL;" << endl;
3497          out << "   }" << endl;
3498          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
3499          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
3500          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
3501          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
3502          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
3503          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
3504          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
3505          out << "   // Check if the cuts configuration file was provided" << endl;
3506          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
3507          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
3508          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3509          out << "   }" << endl;
3510          if (fFriendChainName=="") {
3511             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3512          } else {
3513             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
3514             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
3515             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
3516          }
3517          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
3518          out << "   chain->ls();" << endl;
3519          out << "   return chain;" << endl;
3520          out << "}" << endl << endl;
3521          if (gSystem->AccessPathName("ConfigureCuts.C")) {
3522             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
3523             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
3524             msg += "                      AliLHCTagCuts *lhcCuts,\n";
3525             msg += "                      AliDetectorTagCuts *detCuts,\n";
3526             msg += "                      AliEventTagCuts *evCuts)";
3527             Info("WriteAnalysisMacro", "%s", msg.Data());
3528          }
3529       } 
3530       if (!IsUsingTags() || fFriendChainName!="") {
3531          out <<"//________________________________________________________________________________" << endl;
3532          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
3533          out << "{" << endl;
3534          out << "// Create a chain using url's from xml file" << endl;
3535          out << "   TString filename;" << endl;
3536          out << "   Int_t run = 0;" << endl;
3537          if (IsUseMCchain()) {
3538             out << "   TString treename = \"TE\";" << endl;
3539          } else {   
3540             out << "   TString treename = type;" << endl;
3541             out << "   treename.ToLower();" << endl;
3542             out << "   treename += \"Tree\";" << endl;
3543          }   
3544          out << "   printf(\"***************************************\\n\");" << endl;
3545          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
3546          out << "   printf(\"***************************************\\n\");" << endl;
3547          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
3548          out << "   if (!coll) {" << endl;
3549          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3550          out << "      return NULL;" << endl;
3551          out << "   }" << endl;
3552          out << "   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();" << endl;
3553          out << "   TChain *chain = new TChain(treename);" << endl;
3554          if(fFriendChainName!="") {
3555             out << "   TChain *chainFriend = new TChain(treename);" << endl;
3556          }
3557          out << "   coll->Reset();" << endl;
3558          out << "   while (coll->Next()) {" << endl;
3559          out << "      filename = coll->GetTURL("");" << endl;
3560          out << "      if (mgr) {" << endl;
3561          out << "         Int_t nrun = AliAnalysisManager::GetRunFromAlienPath(filename);" << endl;
3562          out << "         if (nrun && nrun != run) {" << endl;
3563          out << "            printf(\"### Run number detected from chain: %d\\n\", nrun);" << endl;
3564          out << "            mgr->SetRunFromPath(nrun);" << endl;
3565          out << "            run = nrun;" << endl;
3566          out << "         }" << endl;
3567          out << "      }" << endl;
3568          out << "      chain->Add(filename);" << endl;
3569          if(fFriendChainName!="") {
3570             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
3571             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3572             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3573             out << "      chainFriend->Add(fileFriend.Data());" << endl;
3574          }
3575          out << "   }" << endl;
3576          out << "   if (!chain->GetNtrees()) {" << endl;
3577          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
3578          out << "      return NULL;" << endl;
3579          out << "   }" << endl;
3580          if(fFriendChainName!="") {
3581             out << "   chain->AddFriend(chainFriend);" << endl;
3582          }
3583          out << "   return chain;" << endl;
3584          out << "}" << endl << endl;
3585       }   
3586       if (hasANALYSISalice) {
3587          out <<"//________________________________________________________________________________" << endl;
3588          out << "Bool_t SetupPar(const char *package) {" << endl;
3589          out << "// Compile the package and set it up." << endl;
3590          out << "   TString pkgdir = package;" << endl;
3591          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3592          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3593          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
3594          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
3595          out << "   // Check for BUILD.sh and execute" << endl;
3596          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3597          out << "      printf(\"*******************************\\n\");" << endl;
3598          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
3599          out << "      printf(\"*******************************\\n\");" << endl;
3600          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3601          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3602          out << "         gSystem->ChangeDirectory(cdir);" << endl;
3603          out << "         return kFALSE;" << endl;
3604          out << "      }" << endl;
3605          out << "   } else {" << endl;
3606          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3607          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3608          out << "      return kFALSE;" << endl;
3609          out << "   }" << endl;
3610          out << "   // Check for SETUP.C and execute" << endl;
3611          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3612          out << "      printf(\"*******************************\\n\");" << endl;
3613          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
3614          out << "      printf(\"*******************************\\n\");" << endl;
3615          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3616          out << "   } else {" << endl;
3617          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3618          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3619          out << "      return kFALSE;" << endl;
3620          out << "   }" << endl;
3621          out << "   // Restore original workdir" << endl;
3622          out << "   gSystem->ChangeDirectory(cdir);" << endl;
3623          out << "   return kTRUE;" << endl;
3624          out << "}" << endl;
3625       }
3626       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
3627    }   
3628    Bool_t copy = kTRUE;
3629    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3630    if (copy) {
3631       CdWork();
3632       TString workdir = gGrid->GetHomeDirectory();
3633       workdir += fGridWorkingDir;
3634       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
3635       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
3636          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
3637          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
3638          if (!copyLocal2Alien("WriteAnalysisMacro","ConfigureCuts.C", 
3639              Form("%s/ConfigureCuts.C", workdir.Data()))) Fatal("","Terminating");
3640 //         TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
3641       }   
3642       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
3643 //      TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
3644       if (!copyLocal2Alien("WriteAnalysisMacro",fAnalysisMacro.Data(), 
3645            Form("alien://%s/%s", workdir.Data(), 
3646            fAnalysisMacro.Data()))) Fatal("","Terminating");
3647    }
3648 }
3649
3650 //______________________________________________________________________________
3651 void AliAnalysisAlien::WriteMergingMacro()
3652 {
3653 // Write a macro to merge the outputs per master job.
3654    if (!fMergeViaJDL) return;
3655    if (!fOutputFiles.Length()) {
3656       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3657       return;
3658    }   
3659    TString mergingMacro = fExecutable;
3660    mergingMacro.ReplaceAll(".sh","_merge.C");
3661    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3662    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3663       ofstream out;
3664       out.open(mergingMacro.Data(), ios::out);
3665       if (!out.good()) {
3666          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3667          return;
3668       }
3669       Bool_t hasSTEERBase = kFALSE;
3670       Bool_t hasESD = kFALSE;
3671       Bool_t hasAOD = kFALSE;
3672       Bool_t hasANALYSIS = kFALSE;
3673       Bool_t hasOADB = kFALSE;
3674       Bool_t hasANALYSISalice = kFALSE;
3675       Bool_t hasCORRFW = kFALSE;
3676       TString func = mergingMacro;
3677       TString comment;
3678       func.ReplaceAll(".C", "");
3679       out << "void " << func.Data() << "(const char *dir, Int_t stage=0)" << endl;
3680       out << "{" << endl;
3681       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
3682       out << "   TStopwatch timer;" << endl;
3683       out << "   timer.Start();" << endl << endl;
3684       // Reset existing include path
3685       out << "// Reset existing include path and add current directory first in the search" << endl;
3686       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
3687       if (!fExecutableCommand.Contains("aliroot")) {
3688          out << "// load base root libraries" << endl;
3689          out << "   gSystem->Load(\"libTree\");" << endl;
3690          out << "   gSystem->Load(\"libGeom\");" << endl;
3691          out << "   gSystem->Load(\"libVMC\");" << endl;
3692          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
3693          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
3694       }   
3695       if (fAdditionalRootLibs.Length()) {
3696          // in principle libtree /lib geom libvmc etc. can go into this list, too
3697          out << "// Add aditional libraries" << endl;
3698          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3699          TIter next(list);
3700          TObjString *str;
3701          while((str=(TObjString*)next())) {
3702             if (str->GetString().Contains(".so"))
3703             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3704          }
3705          if (list) delete list;
3706       }
3707       out << "// Load analysis framework libraries" << endl;
3708       if (!fPackages) {
3709          if (!fExecutableCommand.Contains("aliroot")) {
3710             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3711             out << "   gSystem->Load(\"libESD\");" << endl;
3712             out << "   gSystem->Load(\"libAOD\");" << endl;
3713          }
3714          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3715          out << "   gSystem->Load(\"libOADB\");" << endl;
3716          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3717          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3718       } else {
3719          TIter next(fPackages);
3720          TObject *obj;
3721          TString pkgname;
3722          TString setupPar = "AliAnalysisAlien::SetupPar";
3723          while ((obj=next())) {
3724             pkgname = obj->GetName();
3725             if (pkgname == "STEERBase" ||
3726                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3727             if (pkgname == "ESD" ||
3728                 pkgname == "ESD.par")       hasESD = kTRUE;
3729             if (pkgname == "AOD" ||
3730                 pkgname == "AOD.par")       hasAOD = kTRUE;
3731             if (pkgname == "ANALYSIS" ||
3732                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
3733             if (pkgname == "OADB" ||
3734                 pkgname == "OADB.par")      hasOADB = kTRUE;
3735             if (pkgname == "ANALYSISalice" ||
3736                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3737             if (pkgname == "CORRFW" ||
3738                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
3739          }   
3740          if (hasANALYSISalice) setupPar = "SetupPar";   
3741          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3742          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3743          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
3744          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
3745          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
3746          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
3747          out << "   gSystem->Load(\"libOADB\");" << endl;
3748          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3749          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3750          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
3751          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
3752          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3753          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3754          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3755          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3756          out << "// Compile other par packages" << endl;
3757          next.Reset();
3758          while ((obj=next())) {
3759             pkgname = obj->GetName();
3760             if (pkgname == "STEERBase" ||
3761                 pkgname == "STEERBase.par" ||
3762                 pkgname == "ESD" ||
3763                 pkgname == "ESD.par" ||
3764                 pkgname == "AOD" ||
3765                 pkgname == "AOD.par" ||
3766                 pkgname == "ANALYSIS" ||
3767                 pkgname == "ANALYSIS.par" ||
3768                 pkgname == "OADB" ||
3769                 pkgname == "OADB.par" ||
3770                 pkgname == "ANALYSISalice" ||
3771                 pkgname == "ANALYSISalice.par" ||
3772                 pkgname == "CORRFW" ||
3773                 pkgname == "CORRFW.par") continue;
3774             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3775          }   
3776       }   
3777       out << "// include path" << endl;
3778       // Get the include path from the interpreter and remove entries pointing to AliRoot
3779       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
3780       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3781       out << "   TIter nextpath(listpaths);" << endl;
3782       out << "   TObjString *pname;" << endl;
3783       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
3784       out << "      TString current = pname->GetName();" << endl;
3785       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3786       out << "      gSystem->AddIncludePath(current);" << endl;
3787       out << "   }" << endl;
3788       out << "   if (listpaths) delete listpaths;" << endl;
3789       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3790       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3791       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3792       if (fAdditionalLibs.Length()) {
3793          out << "// Add aditional AliRoot libraries" << endl;
3794          TObjArray *list = fAdditionalLibs.Tokenize(" ");
3795          TIter next(list);
3796          TObjString *str;
3797          while((str=(TObjString*)next())) {
3798             if (str->GetString().Contains(".so"))
3799                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3800          }
3801          if (list) delete list;
3802       }
3803       out << endl;
3804       out << "// Analysis source to be compiled at runtime (if any)" << endl;
3805       if (fAnalysisSource.Length()) {
3806          TObjArray *list = fAnalysisSource.Tokenize(" ");
3807          TIter next(list);
3808          TObjString *str;
3809          while((str=(TObjString*)next())) {
3810             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3811          }   
3812          if (list) delete list;
3813       }
3814       out << endl;      
3815
3816       if (fFastReadOption) {
3817          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 !!!");
3818          out << "// fast xrootd reading enabled" << endl;
3819          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3820          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3821          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3822          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3823          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3824          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3825       }
3826       // Change temp directory to current one
3827       out << "// Set temporary merging directory to current one" << endl;
3828       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
3829       out << "// Set temporary compilation directory to current one" << endl;
3830       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
3831       out << "// Connect to AliEn" << endl;
3832       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
3833       out << "   TString outputDir = dir;" << endl;  
3834       out << "   TString outputFiles = \"" << GetListOfFiles("out") << "\";" << endl;
3835       out << "   TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
3836       out << "   TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
3837       out << "   TIter *iter = new TIter(list);" << endl;
3838       out << "   TObjString *str;" << endl;
3839       out << "   TString outputFile;" << endl;
3840       out << "   Bool_t merged = kTRUE;" << endl;
3841       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
3842       out << "      outputFile = str->GetString();" << endl;
3843       out << "      if (outputFile.Contains(\"*\")) continue;" << endl;
3844       out << "      Int_t index = outputFile.Index(\"@\");" << endl;
3845       out << "      if (index > 0) outputFile.Remove(index);" << endl;
3846       out << "      // Skip already merged outputs" << endl;
3847       out << "      if (!gSystem->AccessPathName(outputFile)) {" << endl;
3848       out << "         printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
3849       out << "         continue;" << endl;
3850       out << "      }" << endl;
3851       out << "      if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
3852       out << "      merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage);" << endl;
3853       out << "      if (!merged) {" << endl;
3854       out << "         printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
3855       out << "         return;" << endl;
3856       out << "      }" << endl;
3857       out << "   }" << endl;
3858       out << "   // all outputs merged, validate" << endl;
3859       out << "   ofstream out;" << endl;
3860       out << "   out.open(\"outputs_valid\", ios::out);" << endl;
3861       out << "   out.close();" << endl;
3862       out << "   // read the analysis manager from file" << endl;
3863       TString analysisFile = fExecutable;
3864       analysisFile.ReplaceAll(".sh", ".root");
3865       out << "   if (!outputDir.Contains(\"Stage\")) return;" << endl;
3866       out << "   AliAnalysisManager *mgr = AliAnalysisAlien::LoadAnalysisManager(\"" 
3867           << analysisFile << "\");" << endl;
3868       out << "   if (!mgr) return;" << endl;
3869       out << "   mgr->SetRunFromPath(mgr->GetRunFromAlienPath(dir));" << endl;
3870       out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
3871       out << "   mgr->PrintStatus();" << endl;
3872       if (AliAnalysisManager::GetAnalysisManager()) {
3873          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3874             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3875          } else {
3876             if (TestBit(AliAnalysisGrid::kTest))            
3877                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3878             else
3879                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3880          }
3881       }   
3882       out << "   TTree *tree = NULL;" << endl;
3883       out << "   mgr->StartAnalysis(\"gridterminate\", tree);" << endl;
3884       out << "}" << endl << endl;
3885       if (hasANALYSISalice) {
3886          out <<"//________________________________________________________________________________" << endl;
3887          out << "Bool_t SetupPar(const char *package) {" << endl;
3888          out << "// Compile the package and set it up." << endl;
3889          out << "   TString pkgdir = package;" << endl;
3890          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3891          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3892          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
3893          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
3894          out << "   // Check for BUILD.sh and execute" << endl;
3895          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3896          out << "      printf(\"*******************************\\n\");" << endl;
3897          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
3898          out << "      printf(\"*******************************\\n\");" << endl;
3899          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3900          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3901          out << "         gSystem->ChangeDirectory(cdir);" << endl;
3902          out << "         return kFALSE;" << endl;
3903          out << "      }" << endl;
3904          out << "   } else {" << endl;
3905          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3906          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3907          out << "      return kFALSE;" << endl;
3908          out << "   }" << endl;
3909          out << "   // Check for SETUP.C and execute" << endl;
3910          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3911          out << "      printf(\"*******************************\\n\");" << endl;
3912          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
3913          out << "      printf(\"*******************************\\n\");" << endl;
3914          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3915          out << "   } else {" << endl;
3916          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3917          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3918          out << "      return kFALSE;" << endl;
3919          out << "   }" << endl;
3920          out << "   // Restore original workdir" << endl;
3921          out << "   gSystem->ChangeDirectory(cdir);" << endl;
3922          out << "   return kTRUE;" << endl;
3923          out << "}" << endl;
3924       }
3925    }   
3926    Bool_t copy = kTRUE;
3927    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3928    if (copy) {
3929       CdWork();
3930       TString workdir = gGrid->GetHomeDirectory();
3931       workdir += fGridWorkingDir;
3932       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
3933       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
3934 //      TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
3935       if (!copyLocal2Alien("WriteMergeMacro",mergingMacro.Data(), 
3936            Form("%s/%s", workdir.Data(), mergingMacro.Data()))) Fatal("","Terminating");
3937    }
3938 }
3939
3940 //______________________________________________________________________________
3941 Bool_t AliAnalysisAlien::SetupPar(const char *package)
3942 {
3943 // Compile the par file archive pointed by <package>. This must be present in the current directory.
3944 // Note that for loading the compiled library. The current directory should have precedence in
3945 // LD_LIBRARY_PATH
3946    TString pkgdir = package;
3947    pkgdir.ReplaceAll(".par","");
3948    gSystem->Exec(TString::Format("tar xzf %s.par", pkgdir.Data()));
3949    TString cdir = gSystem->WorkingDirectory();
3950    gSystem->ChangeDirectory(pkgdir);
3951    // Check for BUILD.sh and execute
3952    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
3953       printf("**************************************************\n");
3954       printf("*** Building PAR archive %s\n", package);
3955       printf("**************************************************\n");
3956       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
3957          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
3958          gSystem->ChangeDirectory(cdir);
3959          return kFALSE;
3960       }
3961    } else {
3962       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
3963       gSystem->ChangeDirectory(cdir);
3964       return kFALSE;
3965    }
3966    // Check for SETUP.C and execute
3967    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
3968       printf("**************************************************\n");
3969       printf("*** Setup PAR archive %s\n", package);
3970       printf("**************************************************\n");
3971       gROOT->Macro("PROOF-INF/SETUP.C");
3972       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
3973    } else {
3974       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
3975       gSystem->ChangeDirectory(cdir);
3976       return kFALSE;
3977    }   
3978    // Restore original workdir
3979    gSystem->ChangeDirectory(cdir);
3980    return kTRUE;
3981 }
3982
3983 //______________________________________________________________________________
3984 void AliAnalysisAlien::WriteExecutable()
3985 {
3986 // Generate the alien executable script.
3987    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3988       ofstream out;
3989       out.open(fExecutable.Data(), ios::out);
3990       if (out.bad()) {
3991          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
3992          return;
3993       }
3994       out << "#!/bin/bash" << endl;
3995       // Make sure we can properly compile par files
3996       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3997       out << "echo \"=========================================\"" << endl; 
3998       out << "echo \"############## PATH : ##############\"" << endl;
3999       out << "echo $PATH" << endl;
4000       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
4001       out << "echo $LD_LIBRARY_PATH" << endl;
4002       out << "echo \"############## ROOTSYS : ##############\"" << endl;
4003       out << "echo $ROOTSYS" << endl;
4004       out << "echo \"############## which root : ##############\"" << endl;
4005       out << "which root" << endl;
4006       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
4007       out << "echo $ALICE_ROOT" << endl;
4008       out << "echo \"############## which aliroot : ##############\"" << endl;
4009       out << "which aliroot" << endl;
4010       out << "echo \"############## system limits : ##############\"" << endl;
4011       out << "ulimit -a" << endl;
4012       out << "echo \"############## memory : ##############\"" << endl;
4013       out << "free -m" << endl;
4014       out << "echo \"=========================================\"" << endl << endl;
4015       out << fExecutableCommand << " "; 
4016       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
4017       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
4018       out << "echo \"############## memory after: ##############\"" << endl;
4019       out << "free -m" << endl;
4020    }   
4021    Bool_t copy = kTRUE;
4022    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4023    if (copy) {
4024       CdWork();
4025       TString workdir = gGrid->GetHomeDirectory();
4026       TString bindir = Form("%s/bin", workdir.Data());
4027       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
4028       workdir += fGridWorkingDir;
4029       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
4030       if (FileExists(executable)) gGrid->Rm(executable);
4031       Info("WriteExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
4032 //      TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
4033       if (!copyLocal2Alien("WriteExecutable",fExecutable.Data(), 
4034           executable.Data())) Fatal("","Terminating");
4035    } 
4036 }
4037
4038 //______________________________________________________________________________
4039 void AliAnalysisAlien::WriteMergeExecutable()
4040 {
4041 // Generate the alien executable script for the merging job.
4042    if (!fMergeViaJDL) return;
4043    TString mergeExec = fExecutable;
4044    mergeExec.ReplaceAll(".sh", "_merge.sh");
4045    if (!TestBit(AliAnalysisGrid::kSubmit)) {
4046       ofstream out;
4047       out.open(mergeExec.Data(), ios::out);
4048       if (out.bad()) {
4049          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
4050          return;
4051       }
4052       out << "#!/bin/bash" << endl;
4053       // Make sure we can properly compile par files
4054       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
4055       out << "echo \"=========================================\"" << endl; 
4056       out << "echo \"############## PATH : ##############\"" << endl;
4057       out << "echo $PATH" << endl;
4058       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
4059       out << "echo $LD_LIBRARY_PATH" << endl;
4060       out << "echo \"############## ROOTSYS : ##############\"" << endl;
4061       out << "echo $ROOTSYS" << endl;
4062       out << "echo \"############## which root : ##############\"" << endl;
4063       out << "which root" << endl;
4064       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
4065       out << "echo $ALICE_ROOT" << endl;
4066       out << "echo \"############## which aliroot : ##############\"" << endl;
4067       out << "which aliroot" << endl;
4068       out << "echo \"############## system limits : ##############\"" << endl;
4069       out << "ulimit -a" << endl;
4070       out << "echo \"############## memory : ##############\"" << endl;
4071       out << "free -m" << endl;
4072       out << "echo \"=========================================\"" << endl << endl;
4073       TString mergeMacro = fExecutable;
4074       mergeMacro.ReplaceAll(".sh", "_merge.C");
4075       if (IsOneStageMerging())
4076          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
4077       else
4078          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2)\"" << endl;
4079       out << fExecutableCommand << " " << "$ARG" << endl; 
4080       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
4081       out << "echo \"############## memory after: ##############\"" << endl;
4082       out << "free -m" << endl;
4083    }   
4084    Bool_t copy = kTRUE;
4085    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4086    if (copy) {
4087       CdWork();
4088       TString workdir = gGrid->GetHomeDirectory();
4089       TString bindir = Form("%s/bin", workdir.Data());
4090       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
4091       workdir += fGridWorkingDir;
4092       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
4093       if (FileExists(executable)) gGrid->Rm(executable);
4094       Info("WriteMergeExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
4095 //      TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
4096       if (!copyLocal2Alien("WriteMergeExecutable",
4097           mergeExec.Data(), executable.Data())) Fatal("","Terminating");
4098    } 
4099 }
4100
4101 //______________________________________________________________________________
4102 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
4103 {
4104 // Write the production file to be submitted by LPM manager. The format is:
4105 // First line: full_path_to_jdl estimated_no_subjobs_per_master
4106 // Next lines: full_path_to_dataset XXX (XXX is a string)
4107 // To submit, one has to: submit jdl XXX for all lines
4108    ofstream out;
4109    out.open(filename, ios::out);
4110    if (out.bad()) {
4111       Error("WriteProductionFile", "Bad file name: %s", filename);
4112       return;
4113    }
4114    TString workdir;
4115    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice"))
4116       workdir = gGrid->GetHomeDirectory();
4117    workdir += fGridWorkingDir;
4118    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
4119    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
4120    out << locjdl << " " << njobspermaster << endl;
4121    Int_t nmasterjobs = fInputFiles->GetEntries();
4122    for (Int_t i=0; i<nmasterjobs; i++) {
4123       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
4124       runOutDir.ReplaceAll(".xml", "");
4125       if (fOutputToRunNo)
4126          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
4127       else
4128          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
4129    }
4130    if (gGrid) {
4131       Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
4132       if (FileExists(filename)) gGrid->Rm(filename);
4133 //      TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
4134       if (!copyLocal2Alien("WriteProductionFile", filename, 
4135           Form("%s/%s", workdir.Data(),filename))) Fatal("","Terminating");
4136    }   
4137 }
4138
4139 //______________________________________________________________________________
4140 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
4141 {
4142 // Generate the alien validation script.
4143    // Generate the validation script
4144    TObjString *os;
4145    if (fValidationScript.IsNull()) {
4146       fValidationScript = fExecutable;
4147       fValidationScript.ReplaceAll(".sh", "_validation.sh");
4148    }   
4149    TString validationScript = fValidationScript;
4150    if (merge) validationScript.ReplaceAll(".sh", "_merge.sh");
4151    if (!Connect()) {
4152       Error("WriteValidationScript", "Alien connection required");
4153       return;
4154    }
4155    if (!fTerminateFiles.IsNull()) {
4156       fTerminateFiles.Strip();
4157       fTerminateFiles.ReplaceAll(" ",",");
4158    }   
4159    TString outStream = "";
4160    if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
4161    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
4162       ofstream out;
4163       out.open(validationScript, ios::out);
4164       out << "#!/bin/bash" << endl;
4165       out << "##################################################" << endl;
4166       out << "validateout=`dirname $0`" << endl;
4167       out << "validatetime=`date`" << endl;
4168       out << "validated=\"0\";" << endl;
4169       out << "error=0" << endl;
4170       out << "if [ -z $validateout ]" << endl;
4171       out << "then" << endl;
4172       out << "    validateout=\".\"" << endl;
4173       out << "fi" << endl << endl;
4174       out << "cd $validateout;" << endl;
4175       out << "validateworkdir=`pwd`;" << endl << endl;
4176       out << "echo \"*******************************************************\"" << outStream << endl;
4177       out << "echo \"* Automatically generated validation script           *\""  << outStream << endl;
4178       out << "" << endl;
4179       out << "echo \"* Time:    $validatetime \""  << outStream << endl;
4180       out << "echo \"* Dir:     $validateout\""  << outStream << endl;
4181       out << "echo \"* Workdir: $validateworkdir\""  << outStream << endl;
4182       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
4183       out << "ls -la ./"  << outStream << endl;
4184       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl << endl;
4185       out << "##################################################" << endl;
4186       out << "" << endl;
4187
4188       out << "if [ ! -f stderr ] ; then" << endl;
4189       out << "   error=1" << endl;
4190       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << outStream << endl;
4191       out << "   echo \"Error = $error\" " << outStream << endl;
4192       out << "fi" << endl;
4193
4194       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
4195       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
4196       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
4197       out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
4198       out << "" << endl;
4199
4200       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
4201       out << "   error=1" << endl;
4202       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << outStream << endl;
4203       out << "   echo \"$parArch\" " << outStream << endl;
4204       out << "   echo \"Error = $error\" " << outStream << endl;
4205       out << "fi" << endl;
4206
4207       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
4208       out << "   error=1" << endl;
4209       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << outStream << endl;
4210       out << "   echo \"$segViol\" " << outStream << endl;
4211       out << "   echo \"Error = $error\" " << outStream << endl;
4212       out << "fi" << endl;
4213
4214       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
4215       out << "   error=1" << endl;
4216       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << outStream << endl;
4217       out << "   echo \"$segFault\" " << outStream << endl;
4218       out << "   echo \"Error = $error\" " << outStream << endl;
4219       out << "fi" << endl;
4220
4221       out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
4222       out << "   error=1" << endl;
4223       out << "   echo \"* ########## Job not validated - *** glibc detected ***  ###\" " << outStream << endl;
4224       out << "   echo \"$glibcErr\" " << outStream << endl;
4225       out << "   echo \"Error = $error\" " << outStream << endl;
4226       out << "fi" << endl;
4227
4228       // Part dedicated to the specific analyses running into the train
4229
4230       TString outputFiles = fOutputFiles;
4231       if (merge && !fTerminateFiles.IsNull()) {
4232          outputFiles += ",";
4233          outputFiles += fTerminateFiles;
4234       }
4235       TObjArray *arr = outputFiles.Tokenize(",");
4236       TIter next1(arr);
4237       TString outputFile;
4238       while (!merge && (os=(TObjString*)next1())) { 
4239          // No need to validate outputs produced by merging since the merging macro does this
4240          outputFile = os->GetString();
4241          Int_t index = outputFile.Index("@");
4242          if (index > 0) outputFile.Remove(index);
4243          if (fTerminateFiles.Contains(outputFile)) continue;
4244          if (outputFile.Contains("*")) continue;
4245          out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
4246          out << "   error=1" << endl;
4247          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\""  << outStream << endl;
4248          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
4249          out << "fi" << endl;
4250       }   
4251       delete arr;
4252       out << "if ! [ -f outputs_valid ] ; then" << endl;
4253       out << "   error=1" << endl;
4254       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
4255       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
4256       out << "fi" << endl;
4257       
4258       out << "if [ $error = 0 ] ; then" << endl;
4259       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << outStream << endl;
4260       if (!IsKeepLogs()) {
4261          out << "   echo \"* === Logs std* will be deleted === \"" << endl;
4262          outStream = "";
4263          out << "   rm -f std*" << endl;
4264       }            
4265       out << "fi" << endl;
4266
4267       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
4268       out << "echo \"*******************************************************\""  << outStream << endl;
4269       out << "cd -" << endl;
4270       out << "exit $error" << endl;
4271    }    
4272    Bool_t copy = kTRUE;
4273    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4274    if (copy) {
4275       CdWork();
4276       TString workdir = gGrid->GetHomeDirectory();
4277       workdir += fGridWorkingDir;
4278       Info("WriteValidationScript", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
4279       if (FileExists(validationScript)) gGrid->Rm(validationScript);
4280 //      TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
4281       if (!copyLocal2Alien("WriteValidationScript", validationScript.Data(), 
4282           Form("%s/%s",workdir.Data(), validationScript.Data()))) Fatal("","Terminating");
4283    } 
4284 }