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