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