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