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