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