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