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