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