]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
679fba0784ba74c029244d43b670f0b5a3a91d5b
[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       // Check if there is an old active session
2393       Long_t nsessions = gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->QuerySessions(\"\")->GetEntries();", fProofCluster.Data()));
2394       if (nsessions) {
2395          Error("StartAnalysis","You have to reset your old session first\n");
2396          return kFALSE;
2397       }
2398       // Do we need to change the ROOT version ? The success of this cannot be checked.
2399       if (!fRootVersionForProof.IsNull() && !testMode) {
2400          gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"%s\");", 
2401                             fProofCluster.Data(), fRootVersionForProof.Data()));
2402       }
2403       // Connect to PROOF and check the status
2404       Long_t proof = 0;
2405       TString sworkers;
2406       if (fNproofWorkersPerSlave) sworkers = Form("workers=%dx", fNproofWorkersPerSlave);
2407       else if (fNproofWorkers) sworkers = Form("workers=%d", fNproofWorkers);
2408       if (!testMode) {
2409          if (!sworkers.IsNull()) 
2410             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"%s\");", fProofCluster.Data(), sworkers.Data()));
2411          else   
2412             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
2413       } else {
2414          proof = gROOT->ProcessLine("TProof::Open(\"\");");
2415          if (!proof) {
2416             Error("StartAnalysis", "Could not start PROOF in test mode");
2417             return kFALSE;
2418          }   
2419       }
2420       if (!proof) {
2421          Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
2422          return kFALSE;
2423       }   
2424       if (fNproofWorkersPerSlave*fNproofWorkers > 0)
2425          gROOT->ProcessLine(Form("gProof->SetParallel(%d);", fNproofWorkers));
2426       // Is dataset existing ?
2427       if (!testMode) {
2428          TString dataset = fProofDataSet;
2429          Int_t index = dataset.Index("#");
2430          if (index>=0) dataset.Remove(index);
2431 //         if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
2432 //            Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
2433 //            return kFALSE;
2434 //         }
2435 //         Info("StartAnalysis", "Dataset %s found", dataset.Data());
2436       }
2437       // Is ClearPackages() needed ?
2438       if (TestSpecialBit(kClearPackages)) {
2439          Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
2440          gROOT->ProcessLine("gProof->ClearPackages();");
2441       }
2442       // Is a given aliroot mode requested ?
2443       TList optionsList;
2444       TString parLibs;
2445       if (!fAliRootMode.IsNull()) {
2446          TString alirootMode = fAliRootMode;
2447          if (alirootMode == "default") alirootMode = "";
2448          Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
2449          optionsList.SetOwner();
2450          optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
2451          // Check the additional libs to be loaded
2452          TString extraLibs;
2453          Bool_t parMode = kFALSE;
2454          if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:ANALYSISalice";
2455          // Parse the extra libs for .so
2456          if (fAdditionalLibs.Length()) {
2457             TObjArray *list = fAdditionalLibs.Tokenize(" ");
2458             TIter next(list);
2459             TObjString *str;
2460             while((str=(TObjString*)next())) {
2461                if (str->GetString().Contains(".so")) {
2462                   if (parMode) {
2463                      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());
2464                      break;
2465                   }   
2466                   TString stmp = str->GetName();
2467                   if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
2468                   stmp.ReplaceAll(".so","");
2469                   if (!extraLibs.IsNull()) extraLibs += ":";
2470                   extraLibs += stmp;
2471                   continue;
2472                }
2473                if (str->GetString().Contains(".par")) {
2474                   // The first par file found in the list will not allow any further .so
2475                   parMode = kTRUE;
2476                   if (!parLibs.IsNull()) parLibs += ":";
2477                   parLibs += str->GetName();
2478                   continue;
2479                }   
2480             }
2481             if (list) delete list;            
2482          }
2483         if (!extraLibs.IsNull()) {
2484           Info("StartAnalysis", "Adding extra libs: %s",extraLibs.Data());
2485           optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
2486         }
2487          // Check extra includes
2488          if (!fIncludePath.IsNull()) {
2489             TString includePath = fIncludePath;
2490             includePath.ReplaceAll(" ",":");
2491             includePath.ReplaceAll("$ALICE_ROOT/","");
2492             includePath.ReplaceAll("${ALICE_ROOT}/","");
2493             includePath.ReplaceAll("-I","");
2494             includePath.Remove(TString::kTrailing, ':');
2495             Info("StartAnalysis", "Adding extra includes: %s",includePath.Data()); 
2496             optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
2497          }
2498          // Check if connection to grid is requested
2499          if (TestSpecialBit(kProofConnectGrid)) 
2500             optionsList.Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
2501          // Enable AliRoot par
2502          if (testMode) {
2503          // Enable proof lite package
2504             TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
2505             for (Int_t i=0; i<optionsList.GetSize(); i++) {
2506                TNamed *obj = (TNamed*)optionsList.At(i);
2507                printf("%s  %s\n", obj->GetName(), obj->GetTitle());
2508             }   
2509             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
2510               && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)%p);",alirootLite.Data(),&optionsList))) {
2511                   Info("StartAnalysis", "AliRootProofLite enabled");
2512             } else {                      
2513                Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
2514                return kFALSE;
2515             }   
2516          } else {
2517            if ( ! fAliROOTVersion.IsNull() ) {
2518              if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)%p, kTRUE);", 
2519                                          fAliROOTVersion.Data(), &optionsList))) {
2520                 Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
2521                 return kFALSE;
2522              }
2523            }
2524          }
2525          // Enable first par files from fAdditionalLibs
2526          if (!parLibs.IsNull()) {
2527             TObjArray *list = parLibs.Tokenize(":");
2528             TIter next(list);
2529             TObjString *package;
2530             while((package=(TObjString*)next())) {
2531                TString spkg = package->GetName();
2532                spkg.ReplaceAll(".par", "");
2533                gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2534                if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2535                   TString enablePackage = (testMode)?Form("gProof->EnablePackage(\"%s\",kFALSE);", package->GetName()):Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName());
2536                   if (gROOT->ProcessLine(enablePackage)) {
2537                      Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2538                      return kFALSE;
2539                   }
2540                } else {
2541                   Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2542                   return kFALSE;
2543                }
2544             }
2545             if (list) delete list; 
2546          }
2547       } else {
2548          if (fAdditionalLibs.Contains(".so") && !testMode) {
2549             Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
2550                    \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
2551             return kFALSE;       
2552          }
2553       }
2554       // Enable par files if requested
2555       if (fPackages && fPackages->GetEntries()) {
2556          TIter next(fPackages);
2557          TObject *package;
2558          while ((package=next())) {
2559             // Skip packages already enabled
2560             if (parLibs.Contains(package->GetName())) continue;
2561             TString spkg = package->GetName();
2562             spkg.ReplaceAll(".par", "");
2563             gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2564             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2565                if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName()))) {
2566                   Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2567                   return kFALSE;
2568                }
2569             } else {
2570                Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2571                return kFALSE;
2572             }
2573          }
2574       }
2575       // Do we need to load analysis source files ?
2576       // NOTE: don't load on client since this is anyway done by the user to attach his task.
2577       if (fAnalysisSource.Length()) {
2578          TObjArray *list = fAnalysisSource.Tokenize(" ");
2579          TIter next(list);
2580          TObjString *str;
2581          while((str=(TObjString*)next())) {
2582             gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
2583          }
2584          if (list) delete list;
2585       }
2586       if (testMode) {
2587       // Register dataset to proof lite.
2588          if (fFileForTestMode.IsNull()) {
2589             Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2590             return kFALSE;
2591          }
2592          if (gSystem->AccessPathName(fFileForTestMode)) {
2593             Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2594             return kFALSE;
2595          }   
2596          TFileCollection *coll = new TFileCollection();
2597          coll->AddFromFile(fFileForTestMode);
2598          gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)%p, \"OV\");", coll));
2599          gROOT->ProcessLine("gProof->ShowDataSets()");
2600       }
2601       return kTRUE;
2602    }
2603    
2604    // Check if output files have to be taken from the analysis manager
2605    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2606       // Add output files and AOD files
2607       fOutputFiles = GetListOfFiles("outaod");
2608       // Add extra files registered to the analysis manager
2609       TString extra = GetListOfFiles("ext");
2610       if (!extra.IsNull()) {
2611          extra.ReplaceAll(".root", "*.root");
2612          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2613          fOutputFiles += extra;
2614       }
2615       // Compose the output archive.
2616       fOutputArchive = "log_archive.zip:std*@disk=1 ";
2617       fOutputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",fOutputFiles.Data(),fNreplicas);
2618    }
2619 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
2620    if (TestBit(AliAnalysisGrid::kOffline)) {
2621       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2622       \n                         there nor any job run. You can revise the JDL and analysis \
2623       \n                         macro then run the same in \"submit\" mode.");
2624    } else if (TestBit(AliAnalysisGrid::kTest)) {
2625       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
2626       \n                         dataset.");
2627    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2628       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
2629       \n                         space and job submitted.");
2630    } else if (TestBit(AliAnalysisGrid::kMerge)) {
2631       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
2632       if (fMergeViaJDL) CheckInputData();
2633       return kTRUE;
2634    } else {
2635       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
2636    }   
2637       
2638    Print();   
2639    if (!Connect()) {
2640       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
2641       return kFALSE;
2642    }
2643    if (IsCheckCopy() && gGrid) CheckFileCopy(gGrid->GetHomeDirectory());
2644    if (!CheckInputData()) {
2645       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
2646       return kFALSE;
2647    }   
2648    if (!CreateDataset(fDataPattern)) {
2649       TString serror;
2650       if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2651       if (fRunNumbers.Length()) serror = "run numbers";
2652       if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2653       serror += Form("\n   or data pattern <%s>", fDataPattern.Data());
2654       Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2655       return kFALSE;
2656    }   
2657    WriteAnalysisFile();   
2658    WriteAnalysisMacro();
2659    WriteExecutable();
2660    WriteValidationScript();
2661    if (fMergeViaJDL) {
2662       WriteMergingMacro();
2663       WriteMergeExecutable();
2664       WriteValidationScript(kTRUE);
2665    }   
2666    if (!CreateJDL()) return kFALSE;
2667    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2668    if (testMode) {
2669       // Locally testing the analysis
2670       Info("StartAnalysis", "\n_______________________________________________________________________ \
2671       \n   Running analysis script in a daughter shell as on a worker node \
2672       \n_______________________________________________________________________");
2673       TObjArray *list = fOutputFiles.Tokenize(",");
2674       TIter next(list);
2675       TObjString *str;
2676       TString outputFile;
2677       while((str=(TObjString*)next())) {
2678          outputFile = str->GetString();
2679          Int_t index = outputFile.Index("@");
2680          if (index > 0) outputFile.Remove(index);         
2681          if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
2682       }
2683       delete list;
2684       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
2685       gSystem->Exec(Form("bash %s",fValidationScript.Data()));
2686 //      gSystem->Exec("cat stdout");
2687       return kFALSE;
2688    }
2689    // Check if submitting is managed by LPM manager
2690    if (fProductionMode) {
2691       TString prodfile = fJDLName;
2692       prodfile.ReplaceAll(".jdl", ".prod");
2693       WriteProductionFile(prodfile);
2694       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2695       return kFALSE;
2696    }   
2697    // Submit AliEn job(s)
2698    gGrid->Cd(fGridOutputDir);
2699    TGridResult *res;
2700    TString jobID = "";
2701    if (!fRunNumbers.Length() && !fRunRange[0]) {
2702       // Submit a given xml or a set of runs
2703       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
2704       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
2705       if (res) {
2706          const char *cjobId = res->GetKey(0,"jobId");
2707          if (!cjobId) {
2708             gGrid->Stdout();
2709             gGrid->Stderr();
2710             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
2711             return kFALSE;
2712          } else {
2713             Info("StartAnalysis", "\n_______________________________________________________________________ \
2714             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2715             \n_______________________________________________________________________",
2716                    fJDLName.Data(), cjobId);
2717             jobID = cjobId;      
2718          }          
2719          delete res;
2720       } else {
2721          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2722          return kFALSE;      
2723       }   
2724    } else {
2725       // Submit for a range of enumeration of runs.
2726       if (!Submit()) return kFALSE;
2727    }   
2728          
2729    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2730    \n You may exit at any time and terminate the job later using the option <terminate> \
2731    \n ##################################################################################", jobID.Data());
2732    gSystem->Exec("aliensh");
2733    return kTRUE;
2734 }
2735
2736 //______________________________________________________________________________
2737 const char *AliAnalysisAlien::GetListOfFiles(const char *type)
2738 {
2739 // Get a comma-separated list of output files of the requested type.
2740 // Type can be (case unsensitive):
2741 //    aod - list of aod files (std, extensions and filters)
2742 //    out - list of output files connected to containers (but not aod's or extras)
2743 //    ext - list of extra files registered to the manager
2744 //    ter - list of files produced in terminate
2745    static TString files;
2746    files = "";
2747    TString stype = type;
2748    stype.ToLower();
2749    TString aodfiles, extra;
2750    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2751    if (!mgr) {
2752       ::Error("GetListOfFiles", "Cannot call this without analysis manager");
2753       return files.Data();
2754    }
2755    if (mgr->GetOutputEventHandler()) {
2756       aodfiles = mgr->GetOutputEventHandler()->GetOutputFileName();
2757       TString extraaod = mgr->GetOutputEventHandler()->GetExtraOutputs();
2758       if (!extraaod.IsNull()) {
2759          aodfiles += ",";
2760          aodfiles += extraaod;
2761       }
2762    }
2763    if (stype.Contains("aod")) {
2764       files = aodfiles;
2765       if (stype == "aod") return files.Data();
2766    }  
2767    // Add output files that are not in the list of AOD files 
2768    TString outputfiles = "";
2769    TIter next(mgr->GetOutputs());
2770    AliAnalysisDataContainer *output;
2771    const char *filename = 0;
2772    while ((output=(AliAnalysisDataContainer*)next())) {
2773       filename = output->GetFileName();
2774       if (!(strcmp(filename, "default"))) continue;
2775       if (outputfiles.Contains(filename)) continue;
2776       if (aodfiles.Contains(filename))    continue;
2777       if (!outputfiles.IsNull()) outputfiles += ",";
2778       outputfiles += filename;
2779    }
2780    if (stype.Contains("out")) {
2781       if (!files.IsNull()) files += ",";
2782       files += outputfiles;
2783       if (stype == "out") return files.Data();
2784    }   
2785    // Add extra files registered to the analysis manager
2786    TString sextra;
2787    extra = mgr->GetExtraFiles();
2788    if (!extra.IsNull()) {
2789       extra.Strip();
2790       extra.ReplaceAll(" ", ",");
2791       TObjArray *fextra = extra.Tokenize(",");
2792       TIter nextx(fextra);
2793       TObject *obj;
2794       while ((obj=nextx())) {
2795          if (aodfiles.Contains(obj->GetName())) continue;
2796          if (outputfiles.Contains(obj->GetName())) continue;
2797          if (sextra.Contains(obj->GetName())) continue;
2798          if (!sextra.IsNull()) sextra += ",";
2799          sextra += obj->GetName();
2800       }
2801       delete fextra;
2802       if (stype.Contains("ext")) {
2803          if (!files.IsNull()) files += ",";
2804          files += sextra;
2805       }
2806    }   
2807    if (stype == "ext") return files.Data();
2808    TString termfiles;
2809    if (!fTerminateFiles.IsNull()) {
2810       fTerminateFiles.Strip();
2811       fTerminateFiles.ReplaceAll(" ",",");
2812       TObjArray *fextra = fTerminateFiles.Tokenize(",");
2813       TIter nextx(fextra);
2814       TObject *obj;
2815       while ((obj=nextx())) {
2816          if (aodfiles.Contains(obj->GetName())) continue;
2817          if (outputfiles.Contains(obj->GetName())) continue;
2818          if (termfiles.Contains(obj->GetName())) continue;
2819          if (sextra.Contains(obj->GetName())) continue;
2820          if (!termfiles.IsNull()) termfiles += ",";
2821          termfiles += obj->GetName();
2822       }
2823       delete fextra;
2824    }   
2825    if (stype.Contains("ter")) {
2826       if (!files.IsNull() && !termfiles.IsNull()) {
2827          files += ",";
2828          files += termfiles;
2829       }   
2830    }   
2831    return files.Data();
2832 }   
2833
2834 //______________________________________________________________________________
2835 Bool_t AliAnalysisAlien::Submit()
2836 {
2837 // Submit all master jobs.
2838    Int_t nmasterjobs = fInputFiles->GetEntries();
2839    Long_t tshoot = gSystem->Now();
2840    if (!fNsubmitted && !SubmitNext()) return kFALSE;
2841    while (fNsubmitted < nmasterjobs) {
2842       Long_t now = gSystem->Now();
2843       if ((now-tshoot)>30000) {
2844          tshoot = now;
2845          if (!SubmitNext()) return kFALSE;
2846       }   
2847    }
2848    return kTRUE;
2849 }
2850
2851 //______________________________________________________________________________
2852 Bool_t AliAnalysisAlien::SubmitMerging()
2853 {
2854 // Submit all merging jobs.
2855    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2856    gGrid->Cd(fGridOutputDir);
2857    TString mergeJDLName = fExecutable;
2858    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2859    if (!fInputFiles) {
2860       Error("SubmitMerging", "You have to use explicit run numbers or run range to merge via JDL!");
2861       return kFALSE;
2862    }   
2863    Int_t ntosubmit = fInputFiles->GetEntries();
2864    for (Int_t i=0; i<ntosubmit; i++) {
2865       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2866       runOutDir.ReplaceAll(".xml", "");
2867       if (fOutputToRunNo) {
2868          // The output directory is the run number
2869          printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
2870          runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
2871       } else {
2872          if (!fRunNumbers.Length() && !fRunRange[0]) {
2873             // The output directory is the grid outdir
2874             printf("### Submitting merging job for the full output directory %s.\n", fGridOutputDir.Data());
2875             runOutDir = fGridOutputDir;
2876          } else {
2877             // The output directory is the master number in 3 digits format
2878             printf("### Submitting merging job for master <%03d>\n", i);
2879             runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
2880          }   
2881       }
2882       // Check now the number of merging stages.
2883       TObjArray *list = fOutputFiles.Tokenize(",");
2884       TIter next(list);
2885       TObjString *str;
2886       TString outputFile;
2887       while((str=(TObjString*)next())) {
2888          outputFile = str->GetString();
2889          Int_t index = outputFile.Index("@");
2890          if (index > 0) outputFile.Remove(index);
2891          if (!fMergeExcludes.Contains(outputFile)) break;
2892       }
2893       delete list;
2894       Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, mergeJDLName);
2895       if (!done && (i==ntosubmit-1)) return kFALSE;
2896       if (!fRunNumbers.Length() && !fRunRange[0]) break;
2897    }
2898    if (!ntosubmit) return kTRUE;
2899    Info("StartAnalysis", "\n #### STARTING AN ALIEN SHELL FOR YOU. You can exit any time or inspect your jobs in a different shell.##########\
2900                           \n Make sure your jobs are in a final state (you can resubmit failed ones via 'masterjob <id> resubmit ERROR_ALL')\
2901                           \n Rerun in 'terminate' mode to submit all merging stages, each AFTER the previous one completed. The final merged \
2902                           \n output will be written to your alien output directory, while separate stages in <Stage_n>. \
2903                           \n ################################################################################################################");
2904    gSystem->Exec("aliensh");
2905    return kTRUE;
2906 }
2907
2908 //______________________________________________________________________________
2909 Bool_t AliAnalysisAlien::SubmitNext()
2910 {
2911 // Submit next bunch of master jobs if the queue is free. The first master job is
2912 // submitted right away, while the next will not be unless the previous was split.
2913 // The plugin will not submit new master jobs if there are more that 500 jobs in
2914 // waiting phase.
2915    static Bool_t iscalled = kFALSE;
2916    static Int_t firstmaster = 0;
2917    static Int_t lastmaster = 0;
2918    static Int_t npermaster  = 0;
2919    if (iscalled) return kTRUE;
2920    iscalled = kTRUE;
2921    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2922    Int_t ntosubmit = 0;
2923    TGridResult *res;
2924    TString jobID = "";
2925    Int_t nmasterjobs = fInputFiles->GetEntries();
2926    if (!fNsubmitted) {
2927       ntosubmit = 1;
2928       if (!IsUseSubmitPolicy()) {
2929          if (nmasterjobs>5)
2930             Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
2931                 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
2932          ntosubmit = nmasterjobs;
2933       }   
2934    } else {
2935       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
2936       printf("=== master %d: %s\n", lastmaster, status.Data());
2937       // If last master not split, just return
2938       if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
2939       // No more than 100 waiting jobs
2940       if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
2941       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
2942       if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
2943       if (!ntosubmit) ntosubmit = 1;
2944       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
2945              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2946    }
2947    for (Int_t i=0; i<ntosubmit; i++) {
2948       // Submit for a range of enumeration of runs.
2949       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
2950       TString query;
2951       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2952       runOutDir.ReplaceAll(".xml", "");
2953       if (fOutputToRunNo)
2954          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2955       else
2956          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
2957       printf("********* %s\n",query.Data());
2958       res = gGrid->Command(query);
2959       if (res) {
2960          TString cjobId1 = res->GetKey(0,"jobId");
2961          if (!cjobId1.Length()) {
2962             iscalled = kFALSE;
2963             gGrid->Stdout();
2964             gGrid->Stderr();
2965             Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2966             return kFALSE;
2967          } else {
2968             Info("StartAnalysis", "\n_______________________________________________________________________ \
2969             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2970             \n_______________________________________________________________________",
2971                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
2972             jobID += cjobId1;
2973             jobID += " ";
2974             lastmaster = cjobId1.Atoi();
2975             if (!firstmaster) firstmaster = lastmaster;
2976             fNsubmitted++;
2977          }          
2978          delete res;
2979       } else {
2980          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2981          return kFALSE;
2982       }   
2983    }
2984    iscalled = kFALSE;
2985    return kTRUE;
2986 }
2987
2988 //______________________________________________________________________________
2989 void AliAnalysisAlien::WriteAnalysisFile()
2990 {
2991 // Write current analysis manager into the file <analysisFile>
2992    TString analysisFile = fExecutable;
2993    analysisFile.ReplaceAll(".sh", ".root");
2994    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2995       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2996       if (!mgr || !mgr->IsInitialized()) {
2997          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2998          return;
2999       }
3000       // Check analysis type
3001       TObject *handler;
3002       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
3003       handler = (TObject*)mgr->GetInputEventHandler();
3004       if (handler) {
3005          if (handler->InheritsFrom("AliMultiInputEventHandler")) {
3006             AliMultiInputEventHandler *multiIH = (AliMultiInputEventHandler*)handler;
3007             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3008             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
3009          } else {
3010             if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3011             if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
3012          }
3013       }
3014       TDirectory *cdir = gDirectory;
3015       TFile *file = TFile::Open(analysisFile, "RECREATE");
3016       if (file) {
3017          // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
3018          if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
3019          // Unless merging makes no sense
3020          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
3021          mgr->Write();
3022          delete file;
3023          // Enable termination for local jobs
3024          mgr->SetSkipTerminate(kFALSE);
3025       }
3026       if (cdir) cdir->cd();
3027       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
3028    }   
3029    Bool_t copy = kTRUE;
3030    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3031    if (copy) {
3032       CdWork();
3033       TString workdir = gGrid->GetHomeDirectory();
3034       workdir += fGridWorkingDir;
3035       Info("WriteAnalysisFile", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
3036       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
3037       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
3038    }   
3039 }
3040
3041 //______________________________________________________________________________
3042 void AliAnalysisAlien::WriteAnalysisMacro()
3043 {
3044 // Write the analysis macro that will steer the analysis in grid mode.
3045    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3046       ofstream out;
3047       out.open(fAnalysisMacro.Data(), ios::out);
3048       if (!out.good()) {
3049          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3050          return;
3051       }
3052       Bool_t hasSTEERBase = kFALSE;
3053       Bool_t hasESD = kFALSE;
3054       Bool_t hasAOD = kFALSE;
3055       Bool_t hasANALYSIS = kFALSE;
3056       Bool_t hasOADB = kFALSE;
3057       Bool_t hasANALYSISalice = kFALSE;
3058       Bool_t hasCORRFW = kFALSE;
3059       TString func = fAnalysisMacro;
3060       TString type = "ESD";
3061       TString comment = "// Analysis using ";
3062       if (IsUseMCchain()) {
3063          type = "MC";
3064          comment += "MC";
3065       } else {   
3066          if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
3067          if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
3068             type = "AOD";
3069             comment += "AOD";
3070          }   
3071       }
3072       if (type!="AOD" && fFriendChainName!="") {
3073          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
3074          return;
3075       }
3076       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
3077       else comment += " data";
3078       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
3079       func.ReplaceAll(".C", "");
3080       out << "void " << func.Data() << "()" << endl; 
3081       out << "{" << endl;
3082       out << comment.Data() << endl;
3083       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
3084       out << "   TStopwatch timer;" << endl;
3085       out << "   timer.Start();" << endl << endl;
3086       // Change temp directory to current one
3087       out << "// Set temporary merging directory to current one" << endl;
3088       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
3089       out << "// Set temporary compilation directory to current one" << endl;
3090       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
3091       // Reset existing include path
3092       out << "// Reset existing include path and add current directory first in the search" << endl;
3093       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
3094       if (!fExecutableCommand.Contains("aliroot")) {
3095          out << "// load base root libraries" << endl;
3096          out << "   gSystem->Load(\"libTree\");" << endl;
3097          out << "   gSystem->Load(\"libGeom\");" << endl;
3098          out << "   gSystem->Load(\"libVMC\");" << endl;
3099          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
3100          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
3101       }   
3102       if (fAdditionalRootLibs.Length()) {
3103          // in principle libtree /lib geom libvmc etc. can go into this list, too
3104          out << "// Add aditional libraries" << endl;
3105          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3106          TIter next(list);
3107          TObjString *str;
3108          while((str=(TObjString*)next())) {
3109             if (str->GetString().Contains(".so"))
3110             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3111          }
3112          if (list) delete list;
3113       }
3114       out << "// Load analysis framework libraries" << endl;
3115       TString setupPar = "AliAnalysisAlien::SetupPar";
3116       if (!fPackages) {
3117          if (!fExecutableCommand.Contains("aliroot")) {         
3118             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3119             out << "   gSystem->Load(\"libESD\");" << endl;
3120             out << "   gSystem->Load(\"libAOD\");" << endl;
3121          }   
3122          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3123          out << "   gSystem->Load(\"libOADB\");" << endl;
3124          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3125          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3126       } else {
3127          TIter next(fPackages);
3128          TObject *obj;
3129          TString pkgname;
3130          while ((obj=next())) {
3131             pkgname = obj->GetName();
3132             if (pkgname == "STEERBase" ||
3133                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3134             if (pkgname == "ESD" ||
3135                 pkgname == "ESD.par")       hasESD = kTRUE;
3136             if (pkgname == "AOD" ||
3137                 pkgname == "AOD.par")       hasAOD = kTRUE;
3138             if (pkgname == "ANALYSIS" ||
3139                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
3140             if (pkgname == "OADB" ||
3141                 pkgname == "OADB.par")      hasOADB = kTRUE;
3142             if (pkgname == "ANALYSISalice" ||
3143                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3144             if (pkgname == "CORRFW" ||
3145                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
3146          }
3147          if (hasANALYSISalice) setupPar = "SetupPar";   
3148          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3149          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3150          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
3151          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
3152          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
3153          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
3154          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3155          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3156          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
3157          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
3158          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3159          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3160          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3161          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3162          out << "// Compile other par packages" << endl;
3163          next.Reset();
3164          while ((obj=next())) {
3165             pkgname = obj->GetName();
3166             if (pkgname == "STEERBase" ||
3167                 pkgname == "STEERBase.par" ||
3168                 pkgname == "ESD" ||
3169                 pkgname == "ESD.par" ||
3170                 pkgname == "AOD" ||
3171                 pkgname == "AOD.par" ||
3172                 pkgname == "ANALYSIS" ||
3173                 pkgname == "ANALYSIS.par" ||
3174                 pkgname == "OADB" ||
3175                 pkgname == "OADB.par" ||
3176                 pkgname == "ANALYSISalice" ||
3177                 pkgname == "ANALYSISalice.par" ||
3178                 pkgname == "CORRFW" ||
3179                 pkgname == "CORRFW.par") continue;
3180             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3181          }   
3182       }   
3183       out << "// include path" << endl;
3184       // Get the include path from the interpreter and remove entries pointing to AliRoot
3185       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
3186       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3187       out << "   TIter nextpath(listpaths);" << endl;
3188       out << "   TObjString *pname;" << endl;
3189       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
3190       out << "      TString current = pname->GetName();" << endl;
3191       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3192       out << "      gSystem->AddIncludePath(current);" << endl;
3193       out << "   }" << endl;
3194       out << "   if (listpaths) delete listpaths;" << endl;
3195       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3196       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3197       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3198       if (fAdditionalLibs.Length()) {
3199          out << "// Add aditional AliRoot libraries" << endl;
3200          TObjArray *list = fAdditionalLibs.Tokenize(" ");
3201          TIter next(list);
3202          TObjString *str;
3203          while((str=(TObjString*)next())) {
3204             if (str->GetString().Contains(".so"))
3205                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3206             if (str->GetString().Contains(".par"))
3207                out << "   if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
3208          }
3209          if (list) delete list;
3210       }
3211       out << endl;
3212       out << "// analysis source to be compiled at runtime (if any)" << endl;
3213       if (fAnalysisSource.Length()) {
3214          TObjArray *list = fAnalysisSource.Tokenize(" ");
3215          TIter next(list);
3216          TObjString *str;
3217          while((str=(TObjString*)next())) {
3218             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3219          }   
3220          if (list) delete list;
3221       }
3222       out << endl;
3223 //      out << "   printf(\"Currently load libraries:\\n\");" << endl;
3224 //      out << "   printf(\"%s\\n\", gSystem->GetLibraries());" << endl;
3225       if (fFastReadOption) {
3226          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 !!! \
3227                 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3228          out << "// fast xrootd reading enabled" << endl;
3229          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3230          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3231          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3232          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3233          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3234          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3235       }   
3236       out << "// connect to AliEn and make the chain" << endl;
3237       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
3238       out << "// read the analysis manager from file" << endl;
3239       TString analysisFile = fExecutable;
3240       analysisFile.ReplaceAll(".sh", ".root");
3241       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
3242       out << "   if (!file) return;" << endl; 
3243       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
3244       out << "   AliAnalysisManager *mgr = 0;" << endl;
3245       out << "   TKey *key;" << endl;
3246       out << "   while ((key=(TKey*)nextkey())) {" << endl;
3247       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
3248       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
3249       out << "   };" << endl;
3250       out << "   if (!mgr) {" << endl;
3251       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file " << analysisFile <<"\");" << endl;
3252       out << "      return;" << endl;
3253       out << "   }" << endl << endl;
3254       out << "   mgr->PrintStatus();" << endl;
3255       if (AliAnalysisManager::GetAnalysisManager()) {
3256          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3257             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3258          } else {
3259             if (TestBit(AliAnalysisGrid::kTest))            
3260                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3261             else
3262                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3263          }
3264       }   
3265       if (IsUsingTags()) {
3266          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
3267       } else {
3268          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;   
3269       }   
3270       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
3271       out << "   timer.Stop();" << endl;
3272       out << "   timer.Print();" << endl;
3273       out << "}" << endl << endl;
3274       if (IsUsingTags()) {
3275          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
3276          out << "{" << endl;
3277          out << "// Create a chain using tags from the xml file." << endl;
3278          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
3279          out << "   if (!coll) {" << endl;
3280          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3281          out << "      return NULL;" << endl;
3282          out << "   }" << endl;
3283          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
3284          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
3285          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
3286          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
3287          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
3288          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
3289          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
3290          out << "   // Check if the cuts configuration file was provided" << endl;
3291          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
3292          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
3293          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3294          out << "   }" << endl;
3295          if (fFriendChainName=="") {
3296             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3297          } else {
3298             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
3299             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
3300             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
3301          }
3302          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
3303          out << "   chain->ls();" << endl;
3304          out << "   return chain;" << endl;
3305          out << "}" << endl << endl;
3306          if (gSystem->AccessPathName("ConfigureCuts.C")) {
3307             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
3308             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
3309             msg += "                      AliLHCTagCuts *lhcCuts,\n";
3310             msg += "                      AliDetectorTagCuts *detCuts,\n";
3311             msg += "                      AliEventTagCuts *evCuts)";
3312             Info("WriteAnalysisMacro", "%s", msg.Data());
3313          }
3314       } 
3315       if (!IsUsingTags() || fFriendChainName!="") {
3316          out <<"//________________________________________________________________________________" << endl;
3317          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
3318          out << "{" << endl;
3319          out << "// Create a chain using url's from xml file" << endl;
3320          out << "   TString filename;" << endl;
3321          out << "   Int_t run = 0;" << endl;
3322          if (IsUseMCchain()) {
3323             out << "   TString treename = \"TE\";" << endl;
3324          } else {   
3325             out << "   TString treename = type;" << endl;
3326             out << "   treename.ToLower();" << endl;
3327             out << "   treename += \"Tree\";" << endl;
3328          }   
3329          out << "   printf(\"***************************************\\n\");" << endl;
3330          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
3331          out << "   printf(\"***************************************\\n\");" << endl;
3332          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
3333          out << "   if (!coll) {" << endl;
3334          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3335          out << "      return NULL;" << endl;
3336          out << "   }" << endl;
3337          out << "   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();" << endl;
3338          out << "   TChain *chain = new TChain(treename);" << endl;
3339          if(fFriendChainName!="") {
3340             out << "   TChain *chainFriend = new TChain(treename);" << endl;
3341          }
3342          out << "   coll->Reset();" << endl;
3343          out << "   while (coll->Next()) {" << endl;
3344          out << "      filename = coll->GetTURL("");" << endl;
3345          out << "      if (mgr) {" << endl;
3346          out << "         Int_t nrun = AliAnalysisManager::GetRunFromAlienPath(filename);" << endl;
3347          out << "         if (nrun && nrun != run) {" << endl;
3348          out << "            printf(\"### Run number detected from chain: %d\\n\", nrun);" << endl;
3349          out << "            mgr->SetRunFromPath(nrun);" << endl;
3350          out << "            run = nrun;" << endl;
3351          out << "         }" << endl;
3352          out << "      }" << endl;
3353          out << "      chain->Add(filename);" << endl;
3354          if(fFriendChainName!="") {
3355             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
3356             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3357             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3358             out << "      chainFriend->Add(fileFriend.Data());" << endl;
3359          }
3360          out << "   }" << endl;
3361          out << "   if (!chain->GetNtrees()) {" << endl;
3362          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
3363          out << "      return NULL;" << endl;
3364          out << "   }" << endl;
3365          if(fFriendChainName!="") {
3366             out << "   chain->AddFriend(chainFriend);" << endl;
3367          }
3368          out << "   return chain;" << endl;
3369          out << "}" << endl << endl;
3370       }   
3371       if (hasANALYSISalice) {
3372          out <<"//________________________________________________________________________________" << endl;
3373          out << "Bool_t SetupPar(const char *package) {" << endl;
3374          out << "// Compile the package and set it up." << endl;
3375          out << "   TString pkgdir = package;" << endl;
3376          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3377          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3378          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
3379          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
3380          out << "   // Check for BUILD.sh and execute" << endl;
3381          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3382          out << "      printf(\"*******************************\\n\");" << endl;
3383          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
3384          out << "      printf(\"*******************************\\n\");" << endl;
3385          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3386          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3387          out << "         gSystem->ChangeDirectory(cdir);" << endl;
3388          out << "         return kFALSE;" << endl;
3389          out << "      }" << endl;
3390          out << "   } else {" << endl;
3391          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3392          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3393          out << "      return kFALSE;" << endl;
3394          out << "   }" << endl;
3395          out << "   // Check for SETUP.C and execute" << endl;
3396          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3397          out << "      printf(\"*******************************\\n\");" << endl;
3398          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
3399          out << "      printf(\"*******************************\\n\");" << endl;
3400          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3401          out << "   } else {" << endl;
3402          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3403          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3404          out << "      return kFALSE;" << endl;
3405          out << "   }" << endl;
3406          out << "   // Restore original workdir" << endl;
3407          out << "   gSystem->ChangeDirectory(cdir);" << endl;
3408          out << "   return kTRUE;" << endl;
3409          out << "}" << endl;
3410       }
3411       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
3412    }   
3413    Bool_t copy = kTRUE;
3414    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3415    if (copy) {
3416       CdWork();
3417       TString workdir = gGrid->GetHomeDirectory();
3418       workdir += fGridWorkingDir;
3419       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
3420       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
3421          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
3422          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
3423          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
3424       }   
3425       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
3426       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
3427    }
3428 }
3429
3430 //______________________________________________________________________________
3431 void AliAnalysisAlien::WriteMergingMacro()
3432 {
3433 // Write a macro to merge the outputs per master job.
3434    if (!fMergeViaJDL) return;
3435    if (!fOutputFiles.Length()) {
3436       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3437       return;
3438    }   
3439    TString mergingMacro = fExecutable;
3440    mergingMacro.ReplaceAll(".sh","_merge.C");
3441    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3442    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3443       ofstream out;
3444       out.open(mergingMacro.Data(), ios::out);
3445       if (!out.good()) {
3446          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3447          return;
3448       }
3449       Bool_t hasSTEERBase = kFALSE;
3450       Bool_t hasESD = kFALSE;
3451       Bool_t hasAOD = kFALSE;
3452       Bool_t hasANALYSIS = kFALSE;
3453       Bool_t hasOADB = kFALSE;
3454       Bool_t hasANALYSISalice = kFALSE;
3455       Bool_t hasCORRFW = kFALSE;
3456       TString func = mergingMacro;
3457       TString comment;
3458       func.ReplaceAll(".C", "");
3459       out << "void " << func.Data() << "(const char *dir, Int_t stage=0)" << endl;
3460       out << "{" << endl;
3461       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
3462       out << "   TStopwatch timer;" << endl;
3463       out << "   timer.Start();" << endl << endl;
3464       // Reset existing include path
3465       out << "// Reset existing include path and add current directory first in the search" << endl;
3466       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
3467       if (!fExecutableCommand.Contains("aliroot")) {
3468          out << "// load base root libraries" << endl;
3469          out << "   gSystem->Load(\"libTree\");" << endl;
3470          out << "   gSystem->Load(\"libGeom\");" << endl;
3471          out << "   gSystem->Load(\"libVMC\");" << endl;
3472          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
3473          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
3474       }   
3475       if (fAdditionalRootLibs.Length()) {
3476          // in principle libtree /lib geom libvmc etc. can go into this list, too
3477          out << "// Add aditional libraries" << endl;
3478          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3479          TIter next(list);
3480          TObjString *str;
3481          while((str=(TObjString*)next())) {
3482             if (str->GetString().Contains(".so"))
3483             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3484          }
3485          if (list) delete list;
3486       }
3487       out << "// Load analysis framework libraries" << endl;
3488       if (!fPackages) {
3489          if (!fExecutableCommand.Contains("aliroot")) {
3490             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3491             out << "   gSystem->Load(\"libESD\");" << endl;
3492             out << "   gSystem->Load(\"libAOD\");" << endl;
3493          }
3494          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3495          out << "   gSystem->Load(\"libOADB\");" << endl;
3496          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3497          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3498       } else {
3499          TIter next(fPackages);
3500          TObject *obj;
3501          TString pkgname;
3502          TString setupPar = "AliAnalysisAlien::SetupPar";
3503          while ((obj=next())) {
3504             pkgname = obj->GetName();
3505             if (pkgname == "STEERBase" ||
3506                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3507             if (pkgname == "ESD" ||
3508                 pkgname == "ESD.par")       hasESD = kTRUE;
3509             if (pkgname == "AOD" ||
3510                 pkgname == "AOD.par")       hasAOD = kTRUE;
3511             if (pkgname == "ANALYSIS" ||
3512                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
3513             if (pkgname == "OADB" ||
3514                 pkgname == "OADB.par")      hasOADB = kTRUE;
3515             if (pkgname == "ANALYSISalice" ||
3516                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3517             if (pkgname == "CORRFW" ||
3518                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
3519          }   
3520          if (hasANALYSISalice) setupPar = "SetupPar";   
3521          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3522          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3523          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
3524          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
3525          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
3526          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
3527          out << "   gSystem->Load(\"libOADB\");" << endl;
3528          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3529          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3530          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
3531          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
3532          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3533          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3534          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3535          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3536          out << "// Compile other par packages" << endl;
3537          next.Reset();
3538          while ((obj=next())) {
3539             pkgname = obj->GetName();
3540             if (pkgname == "STEERBase" ||
3541                 pkgname == "STEERBase.par" ||
3542                 pkgname == "ESD" ||
3543                 pkgname == "ESD.par" ||
3544                 pkgname == "AOD" ||
3545                 pkgname == "AOD.par" ||
3546                 pkgname == "ANALYSIS" ||
3547                 pkgname == "ANALYSIS.par" ||
3548                 pkgname == "OADB" ||
3549                 pkgname == "OADB.par" ||
3550                 pkgname == "ANALYSISalice" ||
3551                 pkgname == "ANALYSISalice.par" ||
3552                 pkgname == "CORRFW" ||
3553                 pkgname == "CORRFW.par") continue;
3554             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3555          }   
3556       }   
3557       out << "// include path" << endl;
3558       // Get the include path from the interpreter and remove entries pointing to AliRoot
3559       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
3560       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3561       out << "   TIter nextpath(listpaths);" << endl;
3562       out << "   TObjString *pname;" << endl;
3563       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
3564       out << "      TString current = pname->GetName();" << endl;
3565       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3566       out << "      gSystem->AddIncludePath(current);" << endl;
3567       out << "   }" << endl;
3568       out << "   if (listpaths) delete listpaths;" << endl;
3569       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3570       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3571       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3572       if (fAdditionalLibs.Length()) {
3573          out << "// Add aditional AliRoot libraries" << endl;
3574          TObjArray *list = fAdditionalLibs.Tokenize(" ");
3575          TIter next(list);
3576          TObjString *str;
3577          while((str=(TObjString*)next())) {
3578             if (str->GetString().Contains(".so"))
3579                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3580          }
3581          if (list) delete list;
3582       }
3583       out << endl;
3584       out << "// Analysis source to be compiled at runtime (if any)" << endl;
3585       if (fAnalysisSource.Length()) {
3586          TObjArray *list = fAnalysisSource.Tokenize(" ");
3587          TIter next(list);
3588          TObjString *str;
3589          while((str=(TObjString*)next())) {
3590             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3591          }   
3592          if (list) delete list;
3593       }
3594       out << endl;      
3595
3596       if (fFastReadOption) {
3597          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 !!!");
3598          out << "// fast xrootd reading enabled" << endl;
3599          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3600          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3601          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3602          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3603          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3604          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3605       }
3606       // Change temp directory to current one
3607       out << "// Set temporary merging directory to current one" << endl;
3608       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
3609       out << "// Set temporary compilation directory to current one" << endl;
3610       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
3611       out << "// Connect to AliEn" << endl;
3612       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
3613       out << "   TString outputDir = dir;" << endl;  
3614       out << "   TString outputFiles = \"" << GetListOfFiles("out") << "\";" << endl;
3615       out << "   TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
3616       out << "   TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
3617       out << "   TIter *iter = new TIter(list);" << endl;
3618       out << "   TObjString *str;" << endl;
3619       out << "   TString outputFile;" << endl;
3620       out << "   Bool_t merged = kTRUE;" << endl;
3621       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
3622       out << "      outputFile = str->GetString();" << endl;
3623       out << "      if (outputFile.Contains(\"*\")) continue;" << endl;
3624       out << "      Int_t index = outputFile.Index(\"@\");" << endl;
3625       out << "      if (index > 0) outputFile.Remove(index);" << endl;
3626       out << "      // Skip already merged outputs" << endl;
3627       out << "      if (!gSystem->AccessPathName(outputFile)) {" << endl;
3628       out << "         printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
3629       out << "         continue;" << endl;
3630       out << "      }" << endl;
3631       out << "      if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
3632       out << "      merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage);" << endl;
3633       out << "      if (!merged) {" << endl;
3634       out << "         printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
3635       out << "         return;" << endl;
3636       out << "      }" << endl;
3637       out << "   }" << endl;
3638       out << "   // all outputs merged, validate" << endl;
3639       out << "   ofstream out;" << endl;
3640       out << "   out.open(\"outputs_valid\", ios::out);" << endl;
3641       out << "   out.close();" << endl;
3642       out << "   // read the analysis manager from file" << endl;
3643       TString analysisFile = fExecutable;
3644       analysisFile.ReplaceAll(".sh", ".root");
3645       out << "   if (!outputDir.Contains(\"Stage\")) return;" << endl;
3646       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
3647       out << "   if (!file) return;" << endl;
3648       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
3649       out << "   AliAnalysisManager *mgr = 0;" << endl;
3650       out << "   TKey *key;" << endl;
3651       out << "   while ((key=(TKey*)nextkey())) {" << endl;
3652       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
3653       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
3654       out << "   };" << endl;
3655       out << "   if (!mgr) {" << endl;
3656       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
3657       out << "      return;" << endl;
3658       out << "   }" << endl << endl;
3659       out << "   mgr->SetRunFromPath(mgr->GetRunFromAlienPath(dir));" << endl;
3660       out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
3661       out << "   mgr->PrintStatus();" << endl;
3662       if (AliAnalysisManager::GetAnalysisManager()) {
3663          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3664             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3665          } else {
3666             if (TestBit(AliAnalysisGrid::kTest))            
3667                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3668             else
3669                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3670          }
3671       }   
3672       out << "   TTree *tree = NULL;" << endl;
3673       out << "   mgr->StartAnalysis(\"gridterminate\", tree);" << endl;
3674       out << "}" << endl << endl;
3675       if (hasANALYSISalice) {
3676          out <<"//________________________________________________________________________________" << endl;
3677          out << "Bool_t SetupPar(const char *package) {" << endl;
3678          out << "// Compile the package and set it up." << endl;
3679          out << "   TString pkgdir = package;" << endl;
3680          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3681          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3682          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
3683          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
3684          out << "   // Check for BUILD.sh and execute" << endl;
3685          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3686          out << "      printf(\"*******************************\\n\");" << endl;
3687          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
3688          out << "      printf(\"*******************************\\n\");" << endl;
3689          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3690          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3691          out << "         gSystem->ChangeDirectory(cdir);" << endl;
3692          out << "         return kFALSE;" << endl;
3693          out << "      }" << endl;
3694          out << "   } else {" << endl;
3695          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3696          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3697          out << "      return kFALSE;" << endl;
3698          out << "   }" << endl;
3699          out << "   // Check for SETUP.C and execute" << endl;
3700          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3701          out << "      printf(\"*******************************\\n\");" << endl;
3702          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
3703          out << "      printf(\"*******************************\\n\");" << endl;
3704          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3705          out << "   } else {" << endl;
3706          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3707          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3708          out << "      return kFALSE;" << endl;
3709          out << "   }" << endl;
3710          out << "   // Restore original workdir" << endl;
3711          out << "   gSystem->ChangeDirectory(cdir);" << endl;
3712          out << "   return kTRUE;" << endl;
3713          out << "}" << endl;
3714       }
3715    }   
3716    Bool_t copy = kTRUE;
3717    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3718    if (copy) {
3719       CdWork();
3720       TString workdir = gGrid->GetHomeDirectory();
3721       workdir += fGridWorkingDir;
3722       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
3723       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
3724       TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
3725    }
3726 }
3727
3728 //______________________________________________________________________________
3729 Bool_t AliAnalysisAlien::SetupPar(const char *package)
3730 {
3731 // Compile the par file archive pointed by <package>. This must be present in the current directory.
3732 // Note that for loading the compiled library. The current directory should have precedence in
3733 // LD_LIBRARY_PATH
3734    TString pkgdir = package;
3735    pkgdir.ReplaceAll(".par","");
3736    gSystem->Exec(TString::Format("tar xzf %s.par", pkgdir.Data()));
3737    TString cdir = gSystem->WorkingDirectory();
3738    gSystem->ChangeDirectory(pkgdir);
3739    // Check for BUILD.sh and execute
3740    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
3741       printf("**************************************************\n");
3742       printf("*** Building PAR archive %s\n", package);
3743       printf("**************************************************\n");
3744       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
3745          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
3746          gSystem->ChangeDirectory(cdir);
3747          return kFALSE;
3748       }
3749    } else {
3750       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
3751       gSystem->ChangeDirectory(cdir);
3752       return kFALSE;
3753    }
3754    // Check for SETUP.C and execute
3755    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
3756       printf("**************************************************\n");
3757       printf("*** Setup PAR archive %s\n", package);
3758       printf("**************************************************\n");
3759       gROOT->Macro("PROOF-INF/SETUP.C");
3760       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
3761    } else {
3762       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
3763       gSystem->ChangeDirectory(cdir);
3764       return kFALSE;
3765    }   
3766    // Restore original workdir
3767    gSystem->ChangeDirectory(cdir);
3768    return kTRUE;
3769 }
3770
3771 //______________________________________________________________________________
3772 void AliAnalysisAlien::WriteExecutable()
3773 {
3774 // Generate the alien executable script.
3775    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3776       ofstream out;
3777       out.open(fExecutable.Data(), ios::out);
3778       if (out.bad()) {
3779          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
3780          return;
3781       }
3782       out << "#!/bin/bash" << endl;
3783       // Make sure we can properly compile par files
3784       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3785       out << "echo \"=========================================\"" << endl; 
3786       out << "echo \"############## PATH : ##############\"" << endl;
3787       out << "echo $PATH" << endl;
3788       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3789       out << "echo $LD_LIBRARY_PATH" << endl;
3790       out << "echo \"############## ROOTSYS : ##############\"" << endl;
3791       out << "echo $ROOTSYS" << endl;
3792       out << "echo \"############## which root : ##############\"" << endl;
3793       out << "which root" << endl;
3794       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3795       out << "echo $ALICE_ROOT" << endl;
3796       out << "echo \"############## which aliroot : ##############\"" << endl;
3797       out << "which aliroot" << endl;
3798       out << "echo \"############## system limits : ##############\"" << endl;
3799       out << "ulimit -a" << endl;
3800       out << "echo \"############## memory : ##############\"" << endl;
3801       out << "free -m" << endl;
3802       out << "echo \"=========================================\"" << endl << endl;
3803       out << fExecutableCommand << " "; 
3804       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
3805       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
3806       out << "echo \"############## memory after: ##############\"" << endl;
3807       out << "free -m" << endl;
3808    }   
3809    Bool_t copy = kTRUE;
3810    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3811    if (copy) {
3812       CdWork();
3813       TString workdir = gGrid->GetHomeDirectory();
3814       TString bindir = Form("%s/bin", workdir.Data());
3815       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
3816       workdir += fGridWorkingDir;
3817       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
3818       if (FileExists(executable)) gGrid->Rm(executable);
3819       Info("WriteExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
3820       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
3821    } 
3822 }
3823
3824 //______________________________________________________________________________
3825 void AliAnalysisAlien::WriteMergeExecutable()
3826 {
3827 // Generate the alien executable script for the merging job.
3828    if (!fMergeViaJDL) return;
3829    TString mergeExec = fExecutable;
3830    mergeExec.ReplaceAll(".sh", "_merge.sh");
3831    if (!TestBit(AliAnalysisGrid::kSubmit)) {
3832       ofstream out;
3833       out.open(mergeExec.Data(), ios::out);
3834       if (out.bad()) {
3835          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
3836          return;
3837       }
3838       out << "#!/bin/bash" << endl;
3839       // Make sure we can properly compile par files
3840       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3841       out << "echo \"=========================================\"" << endl; 
3842       out << "echo \"############## PATH : ##############\"" << endl;
3843       out << "echo $PATH" << endl;
3844       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3845       out << "echo $LD_LIBRARY_PATH" << endl;
3846       out << "echo \"############## ROOTSYS : ##############\"" << endl;
3847       out << "echo $ROOTSYS" << endl;
3848       out << "echo \"############## which root : ##############\"" << endl;
3849       out << "which root" << endl;
3850       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3851       out << "echo $ALICE_ROOT" << endl;
3852       out << "echo \"############## which aliroot : ##############\"" << endl;
3853       out << "which aliroot" << endl;
3854       out << "echo \"############## system limits : ##############\"" << endl;
3855       out << "ulimit -a" << endl;
3856       out << "echo \"############## memory : ##############\"" << endl;
3857       out << "free -m" << endl;
3858       out << "echo \"=========================================\"" << endl << endl;
3859       TString mergeMacro = fExecutable;
3860       mergeMacro.ReplaceAll(".sh", "_merge.C");
3861       if (IsOneStageMerging())
3862          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
3863       else
3864          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2)\"" << endl;
3865       out << fExecutableCommand << " " << "$ARG" << endl; 
3866       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
3867       out << "echo \"############## memory after: ##############\"" << endl;
3868       out << "free -m" << endl;
3869    }   
3870    Bool_t copy = kTRUE;
3871    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3872    if (copy) {
3873       CdWork();
3874       TString workdir = gGrid->GetHomeDirectory();
3875       TString bindir = Form("%s/bin", workdir.Data());
3876       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
3877       workdir += fGridWorkingDir;
3878       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
3879       if (FileExists(executable)) gGrid->Rm(executable);
3880       Info("WriteMergeExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
3881       TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
3882    } 
3883 }
3884
3885 //______________________________________________________________________________
3886 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
3887 {
3888 // Write the production file to be submitted by LPM manager. The format is:
3889 // First line: full_path_to_jdl estimated_no_subjobs_per_master
3890 // Next lines: full_path_to_dataset XXX (XXX is a string)
3891 // To submit, one has to: submit jdl XXX for all lines
3892    ofstream out;
3893    out.open(filename, ios::out);
3894    if (out.bad()) {
3895       Error("WriteProductionFile", "Bad file name: %s", filename);
3896       return;
3897    }
3898    TString workdir;
3899    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice"))
3900       workdir = gGrid->GetHomeDirectory();
3901    workdir += fGridWorkingDir;
3902    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
3903    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
3904    out << locjdl << " " << njobspermaster << endl;
3905    Int_t nmasterjobs = fInputFiles->GetEntries();
3906    for (Int_t i=0; i<nmasterjobs; i++) {
3907       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3908       runOutDir.ReplaceAll(".xml", "");
3909       if (fOutputToRunNo)
3910          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
3911       else
3912          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
3913    }
3914    if (gGrid) {
3915       Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
3916       if (FileExists(filename)) gGrid->Rm(filename);
3917       TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
3918    }   
3919 }
3920
3921 //______________________________________________________________________________
3922 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
3923 {
3924 // Generate the alien validation script.
3925    // Generate the validation script
3926    TObjString *os;
3927    if (fValidationScript.IsNull()) {
3928       fValidationScript = fExecutable;
3929       fValidationScript.ReplaceAll(".sh", "_validation.sh");
3930    }   
3931    TString validationScript = fValidationScript;
3932    if (merge) validationScript.ReplaceAll(".sh", "_merge.sh");
3933    if (!Connect()) {
3934       Error("WriteValidationScript", "Alien connection required");
3935       return;
3936    }
3937    if (!fTerminateFiles.IsNull()) {
3938       fTerminateFiles.Strip();
3939       fTerminateFiles.ReplaceAll(" ",",");
3940    }   
3941    TString outStream = "";
3942    if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
3943    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3944       ofstream out;
3945       out.open(validationScript, ios::out);
3946       out << "#!/bin/bash" << endl;
3947       out << "##################################################" << endl;
3948       out << "validateout=`dirname $0`" << endl;
3949       out << "validatetime=`date`" << endl;
3950       out << "validated=\"0\";" << endl;
3951       out << "error=0" << endl;
3952       out << "if [ -z $validateout ]" << endl;
3953       out << "then" << endl;
3954       out << "    validateout=\".\"" << endl;
3955       out << "fi" << endl << endl;
3956       out << "cd $validateout;" << endl;
3957       out << "validateworkdir=`pwd`;" << endl << endl;
3958       out << "echo \"*******************************************************\"" << outStream << endl;
3959       out << "echo \"* Automatically generated validation script           *\""  << outStream << endl;
3960       out << "" << endl;
3961       out << "echo \"* Time:    $validatetime \""  << outStream << endl;
3962       out << "echo \"* Dir:     $validateout\""  << outStream << endl;
3963       out << "echo \"* Workdir: $validateworkdir\""  << outStream << endl;
3964       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
3965       out << "ls -la ./"  << outStream << endl;
3966       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl << endl;
3967       out << "##################################################" << endl;
3968       out << "" << endl;
3969
3970       out << "if [ ! -f stderr ] ; then" << endl;
3971       out << "   error=1" << endl;
3972       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << outStream << endl;
3973       out << "   echo \"Error = $error\" " << outStream << endl;
3974       out << "fi" << endl;
3975
3976       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
3977       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
3978       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
3979       out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
3980       out << "" << endl;
3981
3982       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
3983       out << "   error=1" << endl;
3984       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << outStream << endl;
3985       out << "   echo \"$parArch\" " << outStream << endl;
3986       out << "   echo \"Error = $error\" " << outStream << endl;
3987       out << "fi" << endl;
3988
3989       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
3990       out << "   error=1" << endl;
3991       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << outStream << endl;
3992       out << "   echo \"$segViol\" " << outStream << endl;
3993       out << "   echo \"Error = $error\" " << outStream << endl;
3994       out << "fi" << endl;
3995
3996       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
3997       out << "   error=1" << endl;
3998       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << outStream << endl;
3999       out << "   echo \"$segFault\" " << outStream << endl;
4000       out << "   echo \"Error = $error\" " << outStream << endl;
4001       out << "fi" << endl;
4002
4003       out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
4004       out << "   error=1" << endl;
4005       out << "   echo \"* ########## Job not validated - *** glibc detected ***  ###\" " << outStream << endl;
4006       out << "   echo \"$glibcErr\" " << outStream << endl;
4007       out << "   echo \"Error = $error\" " << outStream << endl;
4008       out << "fi" << endl;
4009
4010       // Part dedicated to the specific analyses running into the train
4011
4012       TString outputFiles = fOutputFiles;
4013       if (merge && !fTerminateFiles.IsNull()) {
4014          outputFiles += ",";
4015          outputFiles += fTerminateFiles;
4016       }
4017       TObjArray *arr = outputFiles.Tokenize(",");
4018       TIter next1(arr);
4019       TString outputFile;
4020       while (!merge && (os=(TObjString*)next1())) { 
4021          // No need to validate outputs produced by merging since the merging macro does this
4022          outputFile = os->GetString();
4023          Int_t index = outputFile.Index("@");
4024          if (index > 0) outputFile.Remove(index);
4025          if (fTerminateFiles.Contains(outputFile)) continue;
4026          if (outputFile.Contains("*")) continue;
4027          out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
4028          out << "   error=1" << endl;
4029          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\""  << outStream << endl;
4030          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
4031          out << "fi" << endl;
4032       }   
4033       delete arr;
4034       out << "if ! [ -f outputs_valid ] ; then" << endl;
4035       out << "   error=1" << endl;
4036       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
4037       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
4038       out << "fi" << endl;
4039       
4040       out << "if [ $error = 0 ] ; then" << endl;
4041       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << outStream << endl;
4042       if (!IsKeepLogs()) {
4043          out << "   echo \"* === Logs std* will be deleted === \"" << endl;
4044          outStream = "";
4045          out << "   rm -f std*" << endl;
4046       }            
4047       out << "fi" << endl;
4048
4049       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
4050       out << "echo \"*******************************************************\""  << outStream << endl;
4051       out << "cd -" << endl;
4052       out << "exit $error" << endl;
4053    }    
4054    Bool_t copy = kTRUE;
4055    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4056    if (copy) {
4057       CdWork();
4058       TString workdir = gGrid->GetHomeDirectory();
4059       workdir += fGridWorkingDir;
4060       Info("WriteValidationScript", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
4061       if (FileExists(validationScript)) gGrid->Rm(validationScript);
4062       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
4063    } 
4064 }