Corrections for test mode of the plugin in proof.
[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                   fNsubmitted(0),
62                   fProductionMode(0),
63                   fOutputToRunNo(0),
64                   fMergeViaJDL(0),
65                   fFastReadOption(0),
66                   fOverwriteMode(1),
67                   fNreplicas(2),
68                   fNproofWorkers(0),
69                   fProofReset(0),
70                   fRunNumbers(),
71                   fExecutable(),
72                   fExecutableCommand(),
73                   fArguments(),
74                   fExecutableArgs(),
75                   fAnalysisMacro(),
76                   fAnalysisSource(),
77                   fAdditionalRootLibs(),
78                   fAdditionalLibs(),
79                   fSplitMode(),
80                   fAPIVersion(),
81                   fROOTVersion(),
82                   fAliROOTVersion(),
83                   fExternalPackages(),
84                   fUser(),
85                   fGridWorkingDir(),
86                   fGridDataDir(),
87                   fDataPattern(),
88                   fGridOutputDir(),
89                   fOutputArchive(),
90                   fOutputFiles(),
91                   fInputFormat(),
92                   fDatasetName(),
93                   fJDLName(),
94                             fMergeExcludes(),
95                   fIncludePath(),
96                   fCloseSE(),
97                   fFriendChainName(),
98                   fJobTag(),
99                   fOutputSingle(),
100                   fRunPrefix(),
101                   fProofCluster(),
102                   fProofDataSet(),
103                   fFileForTestMode(),
104                   fRootVersionForProof(),
105                   fAliRootMode(),
106                   fInputFiles(0),
107                   fPackages(0)
108 {
109 // Dummy ctor.
110    SetDefaults();
111 }
112
113 //______________________________________________________________________________
114 AliAnalysisAlien::AliAnalysisAlien(const char *name)
115                  :AliAnalysisGrid(name),
116                   fGridJDL(NULL),
117                   fMergingJDL(NULL),
118                   fPrice(0),
119                   fTTL(0),
120                   fSplitMaxInputFileNumber(0),
121                   fMaxInitFailed(0),
122                   fMasterResubmitThreshold(0),
123                   fNtestFiles(0),
124                   fNrunsPerMaster(0),
125                   fMaxMergeFiles(0),
126                   fNsubmitted(0),
127                   fProductionMode(0),
128                   fOutputToRunNo(0),
129                   fMergeViaJDL(0),
130                   fFastReadOption(0),
131                   fOverwriteMode(1),
132                   fNreplicas(2),
133                   fNproofWorkers(0),
134                   fProofReset(0),
135                   fRunNumbers(),
136                   fExecutable(),
137                   fExecutableCommand(),
138                   fArguments(),
139                   fExecutableArgs(),
140                   fAnalysisMacro(),
141                   fAnalysisSource(),
142                   fAdditionalRootLibs(),
143                   fAdditionalLibs(),
144                   fSplitMode(),
145                   fAPIVersion(),
146                   fROOTVersion(),
147                   fAliROOTVersion(),
148                   fExternalPackages(),
149                   fUser(),
150                   fGridWorkingDir(),
151                   fGridDataDir(),
152                   fDataPattern(),
153                   fGridOutputDir(),
154                   fOutputArchive(),
155                   fOutputFiles(),
156                   fInputFormat(),
157                   fDatasetName(),
158                   fJDLName(),
159                   fMergeExcludes(),
160                   fIncludePath(),
161                   fCloseSE(),
162                   fFriendChainName(),
163                   fJobTag(),
164                   fOutputSingle(),
165                   fRunPrefix(),
166                   fProofCluster(),
167                   fProofDataSet(),
168                   fFileForTestMode(),
169                   fRootVersionForProof(),
170                   fAliRootMode(),
171                   fInputFiles(0),
172                   fPackages(0)
173 {
174 // Default ctor.
175    SetDefaults();
176 }
177
178 //______________________________________________________________________________
179 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
180                  :AliAnalysisGrid(other),
181                   fGridJDL(NULL),
182                   fMergingJDL(NULL),
183                   fPrice(other.fPrice),
184                   fTTL(other.fTTL),
185                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
186                   fMaxInitFailed(other.fMaxInitFailed),
187                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
188                   fNtestFiles(other.fNtestFiles),
189                   fNrunsPerMaster(other.fNrunsPerMaster),
190                   fMaxMergeFiles(other.fMaxMergeFiles),
191                   fNsubmitted(other.fNsubmitted),
192                   fProductionMode(other.fProductionMode),
193                   fOutputToRunNo(other.fOutputToRunNo),
194                   fMergeViaJDL(other.fMergeViaJDL),
195                   fFastReadOption(other.fFastReadOption),
196                   fOverwriteMode(other.fOverwriteMode),
197                   fNreplicas(other.fNreplicas),
198                   fNproofWorkers(other.fNproofWorkers),
199                   fProofReset(other.fProofReset),
200                   fRunNumbers(other.fRunNumbers),
201                   fExecutable(other.fExecutable),
202                   fExecutableCommand(other.fExecutableCommand),
203                   fArguments(other.fArguments),
204                   fExecutableArgs(other.fExecutableArgs),
205                   fAnalysisMacro(other.fAnalysisMacro),
206                   fAnalysisSource(other.fAnalysisSource),
207                   fAdditionalRootLibs(other.fAdditionalRootLibs),
208                   fAdditionalLibs(other.fAdditionalLibs),
209                   fSplitMode(other.fSplitMode),
210                   fAPIVersion(other.fAPIVersion),
211                   fROOTVersion(other.fROOTVersion),
212                   fAliROOTVersion(other.fAliROOTVersion),
213                   fExternalPackages(other.fExternalPackages),
214                   fUser(other.fUser),
215                   fGridWorkingDir(other.fGridWorkingDir),
216                   fGridDataDir(other.fGridDataDir),
217                   fDataPattern(other.fDataPattern),
218                   fGridOutputDir(other.fGridOutputDir),
219                   fOutputArchive(other.fOutputArchive),
220                   fOutputFiles(other.fOutputFiles),
221                   fInputFormat(other.fInputFormat),
222                   fDatasetName(other.fDatasetName),
223                   fJDLName(other.fJDLName),
224                   fMergeExcludes(other.fMergeExcludes),
225                   fIncludePath(other.fIncludePath),
226                   fCloseSE(other.fCloseSE),
227                   fFriendChainName(other.fFriendChainName),
228                   fJobTag(other.fJobTag),
229                   fOutputSingle(other.fOutputSingle),
230                   fRunPrefix(other.fRunPrefix),
231                   fProofCluster(other.fProofCluster),
232                   fProofDataSet(other.fProofDataSet),
233                   fFileForTestMode(other.fFileForTestMode),
234                   fRootVersionForProof(other.fRootVersionForProof),
235                   fAliRootMode(other.fAliRootMode),
236                   fInputFiles(0),
237                   fPackages(0)
238 {
239 // Copy ctor.
240    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
241    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
242    fRunRange[0] = other.fRunRange[0];
243    fRunRange[1] = other.fRunRange[1];
244    if (other.fInputFiles) {
245       fInputFiles = new TObjArray();
246       TIter next(other.fInputFiles);
247       TObject *obj;
248       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
249       fInputFiles->SetOwner();
250    }   
251    if (other.fPackages) {
252       fPackages = new TObjArray();
253       TIter next(other.fPackages);
254       TObject *obj;
255       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
256       fPackages->SetOwner();
257    }   
258 }
259
260 //______________________________________________________________________________
261 AliAnalysisAlien::~AliAnalysisAlien()
262 {
263 // Destructor.
264    if (fGridJDL) delete fGridJDL;
265    if (fMergingJDL) delete fMergingJDL;
266    if (fInputFiles) delete fInputFiles;
267    if (fPackages) delete fPackages;
268 }   
269
270 //______________________________________________________________________________
271 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
272 {
273 // Assignment.
274    if (this != &other) {
275       AliAnalysisGrid::operator=(other);
276       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
277       fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
278       fPrice                   = other.fPrice;
279       fTTL                     = other.fTTL;
280       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
281       fMaxInitFailed           = other.fMaxInitFailed;
282       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
283       fNtestFiles              = other.fNtestFiles;
284       fNrunsPerMaster          = other.fNrunsPerMaster;
285       fMaxMergeFiles           = other.fMaxMergeFiles;
286       fNsubmitted              = other.fNsubmitted;
287       fProductionMode          = other.fProductionMode;
288       fOutputToRunNo           = other.fOutputToRunNo;
289       fMergeViaJDL             = other.fMergeViaJDL;
290       fFastReadOption          = other.fFastReadOption;
291       fOverwriteMode           = other.fOverwriteMode;
292       fNreplicas               = other.fNreplicas;
293       fNproofWorkers           = other.fNproofWorkers;
294       fProofReset              = other.fProofReset;
295       fRunNumbers              = other.fRunNumbers;
296       fExecutable              = other.fExecutable;
297       fExecutableCommand       = other.fExecutableCommand;
298       fArguments               = other.fArguments;
299       fExecutableArgs          = other.fExecutableArgs;
300       fAnalysisMacro           = other.fAnalysisMacro;
301       fAnalysisSource          = other.fAnalysisSource;
302       fAdditionalRootLibs      = other.fAdditionalRootLibs;
303       fAdditionalLibs          = other.fAdditionalLibs;
304       fSplitMode               = other.fSplitMode;
305       fAPIVersion              = other.fAPIVersion;
306       fROOTVersion             = other.fROOTVersion;
307       fAliROOTVersion          = other.fAliROOTVersion;
308       fExternalPackages        = other.fExternalPackages;
309       fUser                    = other.fUser;
310       fGridWorkingDir          = other.fGridWorkingDir;
311       fGridDataDir             = other.fGridDataDir;
312       fDataPattern             = other.fDataPattern;
313       fGridOutputDir           = other.fGridOutputDir;
314       fOutputArchive           = other.fOutputArchive;
315       fOutputFiles             = other.fOutputFiles;
316       fInputFormat             = other.fInputFormat;
317       fDatasetName             = other.fDatasetName;
318       fJDLName                 = other.fJDLName;
319       fMergeExcludes           = other.fMergeExcludes;
320       fIncludePath             = other.fIncludePath;
321       fCloseSE                 = other.fCloseSE;
322       fFriendChainName         = other.fFriendChainName;
323       fJobTag                  = other.fJobTag;
324       fOutputSingle            = other.fOutputSingle;
325       fRunPrefix               = other.fRunPrefix;
326       fProofCluster            = other.fProofCluster;
327       fProofDataSet            = other.fProofDataSet;
328       fFileForTestMode         = other.fFileForTestMode;
329       fRootVersionForProof     = other.fRootVersionForProof;
330       fAliRootMode             = other.fAliRootMode;
331       if (other.fInputFiles) {
332          fInputFiles = new TObjArray();
333          TIter next(other.fInputFiles);
334          TObject *obj;
335          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
336          fInputFiles->SetOwner();
337       }   
338       if (other.fPackages) {
339          fPackages = new TObjArray();
340          TIter next(other.fPackages);
341          TObject *obj;
342          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
343          fPackages->SetOwner();
344       }   
345    }
346    return *this;
347 }
348
349 //______________________________________________________________________________
350 void AliAnalysisAlien::AddIncludePath(const char *path)
351 {
352 // Add include path in the remote analysis macro.
353    TString p(path);
354    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
355    else                  fIncludePath += Form("-I%s ", path);
356 }
357
358 //______________________________________________________________________________
359 void AliAnalysisAlien::AddRunNumber(Int_t run)
360 {
361 // Add a run number to the list of runs to be processed.
362    if (fRunNumbers.Length()) fRunNumbers += " ";
363    fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
364 }   
365
366 //______________________________________________________________________________
367 void AliAnalysisAlien::AddRunNumber(const char* run)
368 {
369 // Add a run number to the list of runs to be processed.
370    if (fRunNumbers.Length()) fRunNumbers += " ";
371    fRunNumbers += run;
372 }   
373
374 //______________________________________________________________________________
375 void AliAnalysisAlien::AddDataFile(const char *lfn)
376 {
377 // Adds a data file to the input to be analysed. The file should be a valid LFN
378 // or point to an existing file in the alien workdir.
379    if (!fInputFiles) fInputFiles = new TObjArray();
380    fInputFiles->Add(new TObjString(lfn));
381 }
382
383 //______________________________________________________________________________
384 void AliAnalysisAlien::AddExternalPackage(const char *package)
385 {
386 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
387    if (fExternalPackages) fExternalPackages += " ";
388    fExternalPackages += package;
389 }   
390       
391 //______________________________________________________________________________
392 Bool_t AliAnalysisAlien::Connect()
393 {
394 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
395    if (gGrid && gGrid->IsConnected()) return kTRUE;
396    if (!gGrid) {
397       Info("Connect", "Trying to connect to AliEn ...");
398       TGrid::Connect("alien://");
399    }
400    if (!gGrid || !gGrid->IsConnected()) {
401       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
402       return kFALSE;
403    }  
404    fUser = gGrid->GetUser();
405    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
406    return kTRUE;
407 }
408
409 //______________________________________________________________________________
410 void AliAnalysisAlien::CdWork()
411 {
412 // Check validity of alien workspace. Create directory if possible.
413    if (!Connect()) {
414       Error("CdWork", "Alien connection required");
415       return;
416    } 
417    TString homedir = gGrid->GetHomeDirectory();
418    TString workdir = homedir + fGridWorkingDir;
419    if (DirectoryExists(workdir)) {
420       gGrid->Cd(workdir);
421       return;
422    }   
423    // Work directory not existing - create it
424    gGrid->Cd(homedir);
425    if (gGrid->Mkdir(workdir, "-p")) {
426       gGrid->Cd(fGridWorkingDir);
427       Info("CreateJDL", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
428    } else {
429       Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
430               workdir.Data(), homedir.Data());
431       fGridWorkingDir = "";
432    }          
433 }
434
435 //______________________________________________________________________________
436 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
437 {
438 // Check if file copying is possible.
439    if (!Connect()) {
440       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
441       return kFALSE;
442    }
443    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
444         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
445    // Check if alien_CLOSE_SE is defined
446    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
447    if (!closeSE.IsNull()) {
448       Info("CheckFileCopy", "Your current close storage is pointing to: \
449            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
450    } else {
451       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
452    }        
453    // Check if grid directory exists.
454    if (!DirectoryExists(alienpath)) {
455       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
456       return kFALSE;
457    }
458    TFile f("plugin_test_copy", "RECREATE");
459    // User may not have write permissions to current directory 
460    if (f.IsZombie()) {
461       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
462             gSystem->WorkingDirectory());
463       return kFALSE;
464    }
465    f.Close();
466    if (FileExists(Form("alien://%s/%s",alienpath, f.GetName()))) gGrid->Rm(Form("alien://%s/%s",alienpath, f.GetName()));
467    if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, f.GetName()))) {
468       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
469            \n# 1. Make sure you have write permissions there. If this is the case: \
470            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
471            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
472            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
473            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
474       gSystem->Unlink(f.GetName());
475       return kFALSE;
476    }   
477    gSystem->Unlink(f.GetName());
478    gGrid->Rm(Form("%s%s",alienpath,f.GetName()));
479    Info("CheckFileCopy", "### ...SUCCESS ###");
480    return kTRUE;
481 }   
482
483 //______________________________________________________________________________
484 Bool_t AliAnalysisAlien::CheckInputData()
485 {
486 // Check validity of input data. If necessary, create xml files.
487    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
488       if (!fGridDataDir.Length()) {
489          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
490          return kFALSE;
491       }
492       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
493       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
494          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
495       return kTRUE;
496    }
497    // Process declared files
498    Bool_t isCollection = kFALSE;
499    Bool_t isXml = kFALSE;
500    Bool_t useTags = kFALSE;
501    Bool_t checked = kFALSE;
502    CdWork();
503    TString file;
504    TString workdir = gGrid->GetHomeDirectory();
505    workdir += fGridWorkingDir;
506    if (fInputFiles) {
507       TObjString *objstr;
508       TIter next(fInputFiles);
509       while ((objstr=(TObjString*)next())) {
510          file = workdir;
511          file += "/";
512          file += objstr->GetString();
513          // Store full lfn path
514          if (FileExists(file)) objstr->SetString(file);
515          else {
516             file = objstr->GetName();
517             if (!FileExists(objstr->GetName())) {
518                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
519                      objstr->GetName(), workdir.Data());
520                return kFALSE;
521             }         
522          }
523          Bool_t iscoll, isxml, usetags;
524          CheckDataType(file, iscoll, isxml, usetags);
525          if (!checked) {
526             checked = kTRUE;
527             isCollection = iscoll;
528             isXml = isxml;
529             useTags = usetags;
530             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
531          } else {
532             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
533                Error("CheckInputData", "Some conflict was found in the types of inputs");
534                return kFALSE;
535             } 
536          }
537       }
538    }
539    // Process requested run numbers
540    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
541    // Check validity of alien data directory
542    if (!fGridDataDir.Length()) {
543       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
544       return kFALSE;
545    }
546    if (!DirectoryExists(fGridDataDir)) {
547       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
548       return kFALSE;
549    }
550    if (isCollection) {
551       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
552       return kFALSE;   
553    }
554    
555    if (checked && !isXml) {
556       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
557       return kFALSE;   
558    }
559    // Check validity of run number(s)
560    TObjArray *arr;
561    TObjString *os;
562    Int_t nruns = 0;
563    TString schunk, schunk2;
564    TString path;
565    if (!checked) {
566       checked = kTRUE;
567       useTags = fDataPattern.Contains("tag");
568       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
569    }   
570    if (useTags != fDataPattern.Contains("tag")) {
571       Error("CheckInputData", "Cannot mix input files using/not using tags");
572       return kFALSE;
573    }
574    if (fRunNumbers.Length()) {
575       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
576       arr = fRunNumbers.Tokenize(" ");
577       TIter next(arr);
578       while ((os=(TObjString*)next())) {
579          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
580          if (!DirectoryExists(path)) {
581             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
582             continue;
583          }
584          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
585          TString msg = "\n#####   file: ";
586          msg += path;
587          msg += " type: xml_collection;";
588          if (useTags) msg += " using_tags: Yes";
589          else          msg += " using_tags: No";
590          Info("CheckDataType", "%s", msg.Data());
591          if (fNrunsPerMaster<2) {
592             AddDataFile(Form("%s.xml", os->GetString().Data()));
593          } else {
594             nruns++;
595             if (((nruns-1)%fNrunsPerMaster) == 0) {
596                schunk = os->GetString();
597             }   
598             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
599             schunk += Form("_%s.xml", os->GetString().Data());
600             AddDataFile(schunk);
601          }   
602       }
603       delete arr;   
604    } else {
605       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
606       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
607          path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
608          if (!DirectoryExists(path)) {
609 //            Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
610             continue;
611          }
612          path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
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%d.xml",fRunPrefix.Data(),irun));
621          } else {
622             nruns++;
623             if (((nruns-1)%fNrunsPerMaster) == 0) {
624                schunk = Form("%s%d", fRunPrefix.Data(),irun);
625             }
626             schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
627             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
628             schunk += schunk2;
629             AddDataFile(schunk);
630          }   
631       }
632       if (!fInputFiles) {
633          schunk += schunk2;
634          AddDataFile(schunk);
635       }   
636    }
637    return kTRUE;      
638 }   
639
640 //______________________________________________________________________________
641 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
642 {
643 // Create dataset for the grid data directory + run number.
644    if (TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
645    if (!Connect()) {
646       Error("CreateDataset", "Cannot create dataset with no grid connection");
647       return kFALSE;
648    }   
649
650    // Cd workspace
651    CdWork();
652    TString workdir = gGrid->GetHomeDirectory();
653    workdir += fGridWorkingDir;
654
655    // Compose the 'find' command arguments
656    TString command;
657    TString options = "-x collection ";
658    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
659    TString conditions = "";
660    
661    TString file;
662    TString path;
663    Int_t nruns = 0;
664    TString schunk, schunk2;
665    TGridCollection *cbase=0, *cadd=0;
666    if (!fRunNumbers.Length() && !fRunRange[0]) {
667       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
668       // Make a single data collection from data directory.
669       path = fGridDataDir;
670       if (!DirectoryExists(path)) {
671          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
672          return kFALSE;
673       }   
674 //      CdWork();
675       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
676       else file = Form("%s.xml", gSystem->BaseName(path));
677       if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
678          command = "find ";
679          command += options;
680          command += path;
681          command += " ";
682          command += pattern;
683          command += conditions;
684          printf("command: %s\n", command.Data());
685          TGridResult *res = gGrid->Command(command);
686          if (res) delete res;
687          // Write standard output to file
688          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
689          Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
690          Bool_t nullFile = kFALSE;
691          if (!hasGrep) {
692             Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
693          } else {
694             nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
695             if (nullFile) {
696                Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
697                return kFALSE;
698             }   
699          }         
700       }
701       Bool_t fileExists = FileExists(file);
702       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
703          // Copy xml file to alien space
704          if (fileExists) gGrid->Rm(file);
705          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
706          if (!FileExists(file)) {
707             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
708             return kFALSE;
709          }
710          // Update list of files to be processed.
711       }
712       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
713       return kTRUE;
714    }   
715    // Several runs
716    Bool_t nullResult = kTRUE;
717    if (fRunNumbers.Length()) {
718       TObjArray *arr = fRunNumbers.Tokenize(" ");
719       TObjString *os;
720       TIter next(arr);
721       while ((os=(TObjString*)next())) {
722          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
723          if (!DirectoryExists(path)) continue;
724 //         CdWork();
725          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
726          else file = Form("%s.xml", os->GetString().Data());
727          // If local collection file does not exist, create it via 'find' command.
728          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
729             command = "find ";
730             command += options;
731             command += path;
732             command += pattern;
733             command += conditions;
734             TGridResult *res = gGrid->Command(command);
735             if (res) delete res;
736             // Write standard output to file
737             gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
738             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
739             Bool_t nullFile = kFALSE;
740             if (!hasGrep) {
741                Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
742             } else {
743                nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
744                if (nullFile) {
745                   Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
746                   fRunNumbers.ReplaceAll(os->GetString().Data(), "");
747                   continue;
748                }   
749             }
750             nullResult = kFALSE;         
751          }
752          if (TestBit(AliAnalysisGrid::kTest)) break;
753          // Check if there is one run per master job.
754          if (fNrunsPerMaster<2) {
755             if (FileExists(file)) {
756                if (fOverwriteMode) gGrid->Rm(file);
757                else {
758                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
759                   continue;
760                }   
761             }        
762             // Copy xml file to alien space
763             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
764             if (!FileExists(file)) {
765                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
766                delete arr;
767                return kFALSE;
768             }
769          } else {
770             nruns++;
771             if (((nruns-1)%fNrunsPerMaster) == 0) {
772                schunk = os->GetString();
773                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
774             } else {
775                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
776                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
777                cbase->Add(cadd);
778                delete cadd;
779             }
780             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
781                continue;
782             }   
783             schunk += Form("_%s.xml", os->GetString().Data());
784             if (FileExists(schunk)) {               
785                if (fOverwriteMode) gGrid->Rm(file);
786                else {
787                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
788                   continue;
789                }   
790             }        
791             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
792             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
793             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
794             if (!FileExists(schunk)) {
795                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
796                delete arr;
797                return kFALSE;
798             }
799          }
800       }   
801       delete arr;
802       if (nullResult) {
803          Error("CreateDataset", "No valid dataset corresponding to the query!");
804          return kFALSE;
805       }
806    } else {
807       // Process a full run range.
808       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
809          path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
810          if (!DirectoryExists(path)) continue;
811 //         CdWork();
812          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
813          else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
814          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
815             if (fOverwriteMode) gGrid->Rm(file);
816             else {
817                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
818                continue;
819             }   
820          }
821          // If local collection file does not exist, create it via 'find' command.
822          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
823             command = "find ";
824             command += options;
825             command += path;
826             command += pattern;
827             command += conditions;
828             TGridResult *res = gGrid->Command(command);
829             if (res) delete res;
830             // Write standard output to file
831             gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
832             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
833             Bool_t nullFile = kFALSE;
834             if (!hasGrep) {
835                Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
836             } else {
837                nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
838                if (nullFile) {
839                   Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
840                   continue;
841                }   
842             }
843             nullResult = kFALSE;         
844          }   
845          if (TestBit(AliAnalysisGrid::kTest)) break;
846          // Check if there is one run per master job.
847          if (fNrunsPerMaster<2) {
848             if (FileExists(file)) {
849                if (fOverwriteMode) gGrid->Rm(file);
850                else {
851                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
852                   continue;
853                }   
854             }        
855             // Copy xml file to alien space
856             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
857             if (!FileExists(file)) {
858                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
859                return kFALSE;
860             }
861          } else {
862             nruns++;
863             // Check if the collection for the chunk exist locally.
864             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
865             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
866                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
867                else continue;
868             }   
869             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
870             if (((nruns-1)%fNrunsPerMaster) == 0) {
871                schunk = Form("%s%d", fRunPrefix.Data(), irun);
872                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
873             } else {
874                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
875                cbase->Add(cadd);
876                delete cadd;
877             }
878             schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
879             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
880                continue;
881             }   
882             schunk = schunk2;
883             if (FileExists(schunk)) {
884                if (fOverwriteMode) gGrid->Rm(schunk);
885                else {
886                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
887                   continue;
888                }   
889             }        
890             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
891             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
892             if (FileExists(schunk)) {
893                if (fOverwriteMode) gGrid->Rm(schunk);
894                else {
895                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
896                   continue;
897                }   
898             }   
899             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
900             if (!FileExists(schunk)) {
901                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
902                return kFALSE;
903             }
904          }   
905       }
906       if (nullResult) {
907          Error("CreateDataset", "No valid dataset corresponding to the query!");
908          return kFALSE;
909       }      
910    }      
911    return kTRUE;
912 }
913
914 //______________________________________________________________________________
915 Bool_t AliAnalysisAlien::CreateJDL()
916 {
917 // Generate a JDL file according to current settings. The name of the file is 
918 // specified by fJDLName.
919    Bool_t error = kFALSE;
920    TObjArray *arr = 0;
921    Bool_t copy = kTRUE;
922    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
923    Bool_t generate = kTRUE;
924    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
925    if (!Connect()) {
926       Error("CreateJDL", "Alien connection required");
927       return kFALSE;
928    }   
929    // Check validity of alien workspace
930    CdWork();
931    TString workdir = gGrid->GetHomeDirectory();
932    workdir += fGridWorkingDir;
933    if (generate) {
934       TObjString *os;
935       if (!fInputFiles) {
936          Error("CreateJDL()", "Define some input files for your analysis.");
937          error = kTRUE;
938       }
939       // Compose list of input files   
940       // Check if output files were defined
941       if (!fOutputFiles.Length()) {
942          Error("CreateJDL", "You must define at least one output file");
943          error = kTRUE;
944       }   
945       // Check if an output directory was defined and valid
946       if (!fGridOutputDir.Length()) {
947          Error("CreateJDL", "You must define AliEn output directory");
948          error = kTRUE;
949       } else {
950          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
951          if (!DirectoryExists(fGridOutputDir)) {
952             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
953                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
954             } else {
955                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
956                // error = kTRUE;
957             }
958          }
959          gGrid->Cd(workdir);
960       }   
961       // Exit if any error up to now
962       if (error) return kFALSE;   
963       // Set JDL fields
964       if (!fUser.IsNull()) {
965          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
966          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
967       }   
968       fGridJDL->SetExecutable(fExecutable, "This is the startup script");
969       TString mergeExec = fExecutable;
970       mergeExec.ReplaceAll(".sh", "_merge.sh");
971       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
972       mergeExec.ReplaceAll(".sh", ".C");
973       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
974       if (!fArguments.IsNull())
975          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
976       fMergingJDL->SetArguments("$1 $2 $3"); 
977       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
978       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
979       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
980       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
981         
982       if (fMaxInitFailed > 0) {
983          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
984          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
985       }   
986       if (fSplitMaxInputFileNumber > 0) {
987          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
988          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
989       }   
990       if (fSplitMode.Length()) {
991          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
992          fGridJDL->SetDescription("Split", "We split per SE or file");
993       }   
994       if (!fAliROOTVersion.IsNull()) {
995          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
996          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
997       }   
998       if (!fROOTVersion.IsNull()) {
999          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1000          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1001       }   
1002       if (!fAPIVersion.IsNull()) {
1003          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1004          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1005       }   
1006       if (!fExternalPackages.IsNull()) {
1007          arr = fExternalPackages.Tokenize(" ");
1008          TIter next(arr);
1009          while ((os=(TObjString*)next())) {
1010             TString pkgname = os->GetString();
1011             Int_t index = pkgname.Index("::");
1012             TString pkgversion = pkgname(index+2, pkgname.Length());
1013             pkgname.Remove(index);
1014             fGridJDL->AddToPackages(pkgname, pkgversion);
1015             fMergingJDL->AddToPackages(pkgname, pkgversion);
1016          }   
1017          delete arr;   
1018       }   
1019       fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1020       fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1021       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1022       TString analysisFile = fExecutable;
1023       analysisFile.ReplaceAll(".sh", ".root");
1024       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1025       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1026       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
1027          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
1028       if (fAdditionalLibs.Length()) {
1029          arr = fAdditionalLibs.Tokenize(" ");
1030          TIter next(arr);
1031          while ((os=(TObjString*)next())) {
1032             if (os->GetString().Contains(".so")) continue;
1033             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1034             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1035          }   
1036          delete arr;   
1037       }
1038       if (fPackages) {
1039          TIter next(fPackages);
1040          TObject *obj;
1041          while ((obj=next())) {
1042             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1043             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1044          }
1045       }
1046       if (fOutputArchive.Length()) {
1047          arr = fOutputArchive.Tokenize(" ");
1048          TIter next(arr);
1049          Bool_t first = kTRUE;
1050          const char *comment = "Files to be archived";
1051          const char *comment1 = comment;
1052          while ((os=(TObjString*)next())) {
1053             if (!first) comment = NULL;
1054             if (!os->GetString().Contains("@") && fCloseSE.Length())
1055                fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1056             else
1057                fGridJDL->AddToOutputArchive(os->GetString(), comment);
1058             first = kFALSE;   
1059          }      
1060          delete arr;
1061          TString outputArchive = fOutputArchive;
1062          if (!fMergeExcludes.IsNull()) {
1063             arr = fMergeExcludes.Tokenize(" ");
1064             TIter next1(arr);
1065             while ((os=(TObjString*)next1())) {
1066                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1067                outputArchive.ReplaceAll(os->GetString(),"");
1068             }
1069             delete arr;
1070          }
1071          arr = outputArchive.Tokenize(" ");
1072          TIter next2(arr);
1073          comment = comment1;
1074          first = kTRUE;
1075          while ((os=(TObjString*)next2())) {
1076             if (!first) comment = NULL;
1077             TString currentfile = os->GetString();
1078             currentfile.ReplaceAll(".root", "*.root");
1079             currentfile.ReplaceAll(".zip", "-Stage$2_$3.zip");
1080             if (!currentfile.Contains("@") && fCloseSE.Length())
1081                fMergingJDL->AddToOutputArchive(Form("%s@%s",currentfile.Data(), fCloseSE.Data()), comment); 
1082             else
1083                fMergingJDL->AddToOutputArchive(currentfile, comment);
1084             first = kFALSE;   
1085          }      
1086          delete arr;         
1087       }      
1088       arr = fOutputFiles.Tokenize(",");
1089       TIter next(arr);
1090       Bool_t first = kTRUE;
1091       const char *comment = "Files to be archived";
1092       const char *comment1 = comment;
1093       while ((os=(TObjString*)next())) {
1094          // Ignore ouputs in jdl that are also in outputarchive
1095          TString sout = os->GetString();
1096          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1097          if (fOutputArchive.Contains(sout)) continue;
1098          if (!first) comment = NULL;
1099          if (!os->GetString().Contains("@") && fCloseSE.Length())
1100             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1101          else
1102             fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1103          first = kFALSE;   
1104       }   
1105       delete arr;
1106       if (fOutputFiles.Length()) {
1107          TString outputFiles = fOutputFiles;
1108          if (!fMergeExcludes.IsNull()) {
1109             arr = fMergeExcludes.Tokenize(" ");
1110             TIter next1(arr);
1111             while ((os=(TObjString*)next1())) {
1112                outputFiles.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1113                outputFiles.ReplaceAll(os->GetString(),"");
1114             }
1115             delete arr;
1116          }
1117          arr = outputFiles.Tokenize(" ");
1118          TIter next2(arr);
1119          comment = comment1;
1120          first = kTRUE;
1121          while ((os=(TObjString*)next2())) {
1122             // Ignore ouputs in jdl that are also in outputarchive
1123             TString sout = os->GetString();
1124             if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1125             if (fOutputArchive.Contains(sout)) continue;
1126             if (!first) comment = NULL;
1127             if (!os->GetString().Contains("@") && fCloseSE.Length())
1128                fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1129             else
1130                fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1131             first = kFALSE;   
1132          }   
1133          delete arr;
1134       }
1135       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1136       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1137       TString validationScript = fExecutable;
1138       validationScript.ReplaceAll(".sh", "_validation.sh");
1139       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1140       validationScript = fExecutable;
1141       validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
1142       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1143       if (fMasterResubmitThreshold) {
1144          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1145          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1146       }   
1147       // Write a jdl with 2 input parameters: collection name and output dir name.
1148       WriteJDL(copy);
1149    }
1150    // Copy jdl to grid workspace   
1151    if (copy) {
1152       // Check if an output directory was defined and valid
1153       if (!fGridOutputDir.Length()) {
1154          Error("CreateJDL", "You must define AliEn output directory");
1155          return kFALSE;
1156       } else {
1157          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1158          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1159             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1160                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1161             } else {
1162                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1163                return kFALSE;
1164             }
1165          }
1166          gGrid->Cd(workdir);
1167       }   
1168       if (TestBit(AliAnalysisGrid::kSubmit)) {
1169          TString mergeJDLName = fExecutable;
1170          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1171          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1172          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1173          if (fProductionMode) {
1174             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1175             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1176          }   
1177          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1178          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1179          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1180          TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1181          if (fMergeViaJDL) {
1182             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1183             TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1184          }   
1185       }
1186       if (fAdditionalLibs.Length()) {
1187          arr = fAdditionalLibs.Tokenize(" ");
1188          TObjString *os;
1189          TIter next(arr);
1190          while ((os=(TObjString*)next())) {
1191             if (os->GetString().Contains(".so")) continue;
1192             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1193             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1194             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1195          }   
1196          delete arr;   
1197       }
1198       if (fPackages) {
1199          TIter next(fPackages);
1200          TObject *obj;
1201          while ((obj=next())) {
1202             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1203             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1204             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1205          }   
1206       }      
1207    } 
1208    return kTRUE;
1209 }
1210
1211 //______________________________________________________________________________
1212 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1213 {
1214 // Writes one or more JDL's corresponding to findex. If findex is negative,
1215 // all run numbers are considered in one go (jdl). For non-negative indices
1216 // they correspond to the indices in the array fInputFiles.
1217    if (!fInputFiles) return kFALSE;
1218    TObjString *os;
1219    TString workdir = gGrid->GetHomeDirectory();
1220    workdir += fGridWorkingDir;
1221    
1222    if (!fRunNumbers.Length() && !fRunRange[0]) {
1223       // One jdl with no parameters in case input data is specified by name.
1224       TIter next(fInputFiles);
1225       while ((os=(TObjString*)next()))
1226          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()), "Input xml collections");
1227       if (!fOutputSingle.IsNull())
1228          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1229       else {
1230          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1231          fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1232       }   
1233    } else {
1234       // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1235       fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1236       if (!fOutputSingle.IsNull()) {
1237          if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1238          else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1239       } else {   
1240          fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1241          fMergingJDL->SetOutputDirectory("$1", "Output directory");
1242       }   
1243    }
1244       
1245
1246    // Generate the JDL as a string
1247    TString sjdl = fGridJDL->Generate();
1248    TString sjdl1 = fMergingJDL->Generate();
1249    Int_t index;
1250    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
1251    sjdl.ReplaceAll("(member", "\n   (member");
1252    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1253    sjdl.ReplaceAll("{", "{\n   ");
1254    sjdl.ReplaceAll("};", "\n};");
1255    sjdl.ReplaceAll("{\n   \n", "{\n");
1256    sjdl.ReplaceAll("\n\n", "\n");
1257    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1258    sjdl1.ReplaceAll("\"LF:", "\n   \"LF:");
1259    sjdl1.ReplaceAll("(member", "\n   (member");
1260    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1261    sjdl1.ReplaceAll("{", "{\n   ");
1262    sjdl1.ReplaceAll("};", "\n};");
1263    sjdl1.ReplaceAll("{\n   \n", "{\n");
1264    sjdl1.ReplaceAll("\n\n", "\n");
1265    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1266    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1267    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
1268    index = sjdl.Index("JDLVariables");
1269    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1270    sjdl += "Workdirectorysize = {\"5000MB\"};";
1271    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1272    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", fJobTag.Data()));
1273    sjdl1.Prepend("# Generated merging jdl\n# $1 = full alien path to output directory to be merged\n# $2 = merging stage\n# $3 = merged chunk\n");
1274    index = sjdl1.Index("JDLVariables");
1275    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1276    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1277    // Write jdl to file
1278    ofstream out;
1279    out.open(fJDLName.Data(), ios::out);
1280    if (out.bad()) {
1281       Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1282       return kFALSE;
1283    }
1284    out << sjdl << endl;
1285    TString mergeJDLName = fExecutable;
1286    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1287    if (fMergeViaJDL) {
1288       ofstream out1;
1289       out1.open(mergeJDLName.Data(), ios::out);
1290       if (out.bad()) {
1291          Error("CreateJDL", "Bad file name: %s", mergeJDLName.Data());
1292          return kFALSE;
1293       }
1294       out1 << sjdl1 << endl;
1295    }   
1296
1297    // Copy jdl to grid workspace   
1298    if (!copy) {
1299       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1300    } else {
1301       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1302       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1303       if (fProductionMode) {
1304          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1305          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1306       }   
1307       if (FileExists(locjdl)) gGrid->Rm(locjdl);
1308       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1309       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1310       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1311       if (fMergeViaJDL) {
1312          Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1313          TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1314       }   
1315    } 
1316    return kTRUE;
1317 }
1318
1319 //______________________________________________________________________________
1320 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1321 {
1322 // Returns true if file exists.
1323    if (!gGrid) return kFALSE;
1324    TGridResult *res = gGrid->Ls(lfn);
1325    if (!res) return kFALSE;
1326    TMap *map = dynamic_cast<TMap*>(res->At(0));
1327    if (!map) {
1328       delete res;
1329       return kFALSE;
1330    }   
1331    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1332    if (!objs || !objs->GetString().Length()) {
1333       delete res;
1334       return kFALSE;
1335    }
1336    delete res;   
1337    return kTRUE;
1338 }
1339
1340 //______________________________________________________________________________
1341 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1342 {
1343 // Returns true if directory exists. Can be also a path.
1344    if (!gGrid) return kFALSE;
1345    // Check if dirname is a path
1346    TString dirstripped = dirname;
1347    dirstripped = dirstripped.Strip();
1348    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1349    TString dir = gSystem->BaseName(dirstripped);
1350    dir += "/";
1351    TString path = gSystem->DirName(dirstripped);
1352    TGridResult *res = gGrid->Ls(path, "-F");
1353    if (!res) return kFALSE;
1354    TIter next(res);
1355    TMap *map;
1356    TObject *obj;
1357    while ((map=dynamic_cast<TMap*>(next()))) {
1358       obj = map->GetValue("name");
1359       if (!obj) break;
1360       if (dir == obj->GetName()) {
1361          delete res;
1362          return kTRUE;
1363       }
1364    }
1365    delete res;
1366    return kFALSE;
1367 }      
1368
1369 //______________________________________________________________________________
1370 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
1371 {
1372 // Check input data type.
1373    isCollection = kFALSE;
1374    isXml = kFALSE;
1375    useTags = kFALSE;
1376    if (!gGrid) {
1377       Error("CheckDataType", "No connection to grid");
1378       return;
1379    }
1380    isCollection = IsCollection(lfn);
1381    TString msg = "\n#####   file: ";
1382    msg += lfn;
1383    if (isCollection) {
1384       msg += " type: raw_collection;";
1385    // special treatment for collections
1386       isXml = kFALSE;
1387       // check for tag files in the collection
1388       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1389       if (!res) {
1390          msg += " using_tags: No (unknown)";
1391          Info("CheckDataType", "%s", msg.Data());
1392          return;
1393       }   
1394       const char* typeStr = res->GetKey(0, "origLFN");
1395       if (!typeStr || !strlen(typeStr)) {
1396          msg += " using_tags: No (unknown)";
1397          Info("CheckDataType", "%s", msg.Data());
1398          return;
1399       }   
1400       TString file = typeStr;
1401       useTags = file.Contains(".tag");
1402       if (useTags) msg += " using_tags: Yes";
1403       else          msg += " using_tags: No";
1404       Info("CheckDataType", "%s", msg.Data());
1405       return;
1406    }
1407    TString slfn(lfn);
1408    slfn.ToLower();
1409    isXml = slfn.Contains(".xml");
1410    if (isXml) {
1411    // Open xml collection and check if there are tag files inside
1412       msg += " type: xml_collection;";
1413       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1414       if (!coll) {
1415          msg += " using_tags: No (unknown)";
1416          Info("CheckDataType", "%s", msg.Data());
1417          return;
1418       }   
1419       TMap *map = coll->Next();
1420       if (!map) {
1421          msg += " using_tags: No (unknown)";
1422          Info("CheckDataType", "%s", msg.Data());
1423          return;
1424       }   
1425       map = (TMap*)map->GetValue("");
1426       TString file;
1427       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1428       useTags = file.Contains(".tag");
1429       delete coll;
1430       if (useTags) msg += " using_tags: Yes";
1431       else          msg += " using_tags: No";
1432       Info("CheckDataType", "%s", msg.Data());
1433       return;
1434    }
1435    useTags = slfn.Contains(".tag");
1436    if (slfn.Contains(".root")) msg += " type: root file;";
1437    else                        msg += " type: unknown file;";
1438    if (useTags) msg += " using_tags: Yes";
1439    else          msg += " using_tags: No";
1440    Info("CheckDataType", "%s", msg.Data());
1441 }
1442
1443 //______________________________________________________________________________
1444 void AliAnalysisAlien::EnablePackage(const char *package)
1445 {
1446 // Enables a par file supposed to exist in the current directory.
1447    TString pkg(package);
1448    pkg.ReplaceAll(".par", "");
1449    pkg += ".par";
1450    if (gSystem->AccessPathName(pkg)) {
1451       Fatal("EnablePackage", "Package %s not found", pkg.Data());
1452       return;
1453    }
1454    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1455       Info("EnablePackage", "AliEn plugin will use .par packages");
1456    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1457    if (!fPackages) {
1458       fPackages = new TObjArray();
1459       fPackages->SetOwner();
1460    }
1461    fPackages->Add(new TObjString(pkg));
1462 }      
1463
1464 //______________________________________________________________________________
1465 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
1466 {
1467 // Make a tree from files having the location specified in fFileForTestMode. 
1468 // Inspired from JF's CreateESDChain.
1469    if (fFileForTestMode.IsNull()) {
1470       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
1471       return NULL;
1472    }
1473    if (gSystem->AccessPathName(fFileForTestMode)) {
1474       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
1475       return NULL;
1476    }   
1477    // Open the file
1478    ifstream in;
1479    in.open(fFileForTestMode);
1480    Int_t count = 0;
1481     // Read the input list of files and add them to the chain
1482     TString line;
1483     TChain *chain = new TChain(treeName);
1484     while (in.good())
1485     {
1486       in >> line;
1487       if (line.IsNull()) continue;
1488       if (count++ == fNtestFiles) break;
1489       TString esdFile(line);
1490       TFile *file = TFile::Open(esdFile);
1491       if (file) {
1492          if (!file->IsZombie()) chain->Add(esdFile);
1493          file->Close();
1494       } else {
1495          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
1496       }   
1497     }
1498     in.close();
1499     if (!chain->GetListOfFiles()->GetEntries()) {
1500        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
1501        delete chain;
1502        return NULL;
1503     }
1504 //    chain->ls();
1505     return chain;
1506 }    
1507
1508 //______________________________________________________________________________
1509 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1510 {
1511 // Get job status for all jobs with jobid>jobidstart.
1512    static char mstatus[20];
1513    mstatus[0] = '\0';
1514    nrunning = 0;
1515    nwaiting = 0;
1516    nerror   = 0;
1517    ndone    = 0;
1518    TGridJobStatusList *list = gGrid->Ps("");
1519    if (!list) return mstatus;
1520    Int_t nentries = list->GetSize();
1521    TGridJobStatus *status;
1522    Int_t pid;
1523    for (Int_t ijob=0; ijob<nentries; ijob++) {
1524       status = (TGridJobStatus *)list->At(ijob);
1525       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1526       if (pid<jobidstart) continue;
1527       if (pid == lastid) {
1528          gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1529       }   
1530       switch (status->GetStatus()) {
1531          case TGridJobStatus::kWAITING:
1532             nwaiting++; break;
1533          case TGridJobStatus::kRUNNING:
1534             nrunning++; break;
1535          case TGridJobStatus::kABORTED:
1536          case TGridJobStatus::kFAIL:
1537          case TGridJobStatus::kUNKNOWN:
1538             nerror++; break;
1539          case TGridJobStatus::kDONE:
1540             ndone++;
1541       }
1542    }
1543    list->Delete();
1544    delete list;
1545    return mstatus;
1546 }
1547
1548 //______________________________________________________________________________
1549 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1550 {
1551 // Returns true if file is a collection. Functionality duplicated from
1552 // TAlien::Type() because we don't want to directly depend on TAlien.
1553    if (!gGrid) {
1554       Error("IsCollection", "No connection to grid");
1555       return kFALSE;
1556    }
1557    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1558    if (!res) return kFALSE;
1559    const char* typeStr = res->GetKey(0, "type");
1560    if (!typeStr || !strlen(typeStr)) return kFALSE;
1561    if (!strcmp(typeStr, "collection")) return kTRUE;
1562    delete res;
1563    return kFALSE;
1564 }   
1565
1566 //______________________________________________________________________________
1567 Bool_t AliAnalysisAlien::IsSingleOutput() const
1568 {
1569 // Check if single-ouput option is on.
1570    return (!fOutputSingle.IsNull());
1571 }
1572    
1573 //______________________________________________________________________________
1574 void AliAnalysisAlien::Print(Option_t *) const
1575 {
1576 // Print current plugin settings.
1577    printf("### AliEn analysis plugin current settings ###\n");
1578    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
1579    if (fOverwriteMode) {
1580       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
1581             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
1582    }
1583    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
1584    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
1585    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1586    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1587    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1588    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1589    if (fUser.Length()) 
1590    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1591    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1592    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1593    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1594    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1595    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1596    if (fRunNumbers.Length()) 
1597    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1598    if (fRunRange[0])
1599    printf("=   Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1600    if (!fRunRange[0] && !fRunNumbers.Length()) {
1601       TIter next(fInputFiles);
1602       TObject *obj;
1603       TString list;
1604       while ((obj=next())) list += obj->GetName();
1605       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1606    }
1607    if (TestBit(AliAnalysisGrid::kTest))
1608    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1609    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1610    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1611    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1612    printf("=====================================================================\n");
1613    printf("=   Job price: ___________________________________ %d\n", fPrice);
1614    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
1615    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1616    if (fMaxInitFailed>0) 
1617    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1618    if (fMasterResubmitThreshold>0) 
1619    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1620    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
1621    if (fNrunsPerMaster>0)
1622    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1623    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1624    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
1625    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
1626    if (fArguments.Length()) 
1627    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
1628    if (fExecutableArgs.Length()) 
1629    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1630    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1631    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1632    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1633    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1634    if (fDatasetName)
1635    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1636    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1637    if (fIncludePath.Data())
1638    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1639    if (fCloseSE.Length())
1640    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1641    if (fFriendChainName.Length())
1642    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1643    if (fPackages) {
1644       TIter next(fPackages);
1645       TObject *obj;
1646       TString list;
1647       while ((obj=next())) list += obj->GetName();
1648       printf("=   Par files to be used: ________________________ %s\n", list.Data());
1649    }   
1650 }
1651
1652 //______________________________________________________________________________
1653 void AliAnalysisAlien::SetDefaults()
1654 {
1655 // Set default values for everything. What cannot be filled will be left empty.
1656    if (fGridJDL) delete fGridJDL;
1657    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1658    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1659    fPrice                      = 1;
1660    fTTL                        = 30000;
1661    fSplitMaxInputFileNumber    = 100;
1662    fMaxInitFailed              = 0;
1663    fMasterResubmitThreshold    = 0;
1664    fNtestFiles                 = 10;
1665    fNreplicas                  = 2;
1666    fRunRange[0]                = 0;
1667    fRunRange[1]                = 0;
1668    fNrunsPerMaster             = 1;
1669    fMaxMergeFiles              = 100;
1670    fRunNumbers                 = "";
1671    fExecutable                 = "analysis.sh";
1672    fExecutableCommand          = "root -b -q";
1673    fArguments                  = "";
1674    fExecutableArgs             = "";
1675    fAnalysisMacro              = "myAnalysis.C";
1676    fAnalysisSource             = "";
1677    fAdditionalLibs             = "";
1678    fSplitMode                  = "se";
1679    fAPIVersion                 = "";
1680    fROOTVersion                = "";
1681    fAliROOTVersion             = "";
1682    fUser                       = "";  // Your alien user name
1683    fGridWorkingDir             = "";
1684    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1685    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1686    fFriendChainName            = "";
1687    fGridOutputDir              = "output";
1688    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
1689    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1690    fInputFormat                = "xml-single";
1691    fJDLName                    = "analysis.jdl";
1692    fJobTag                     = "Automatically generated analysis JDL";
1693    fMergeExcludes              = "";
1694    fMergeViaJDL                = 0;
1695    SetUseCopy(kTRUE);
1696    SetCheckCopy(kTRUE);
1697    SetDefaultOutputs(kTRUE);
1698    fOverwriteMode              = 1;
1699 }   
1700
1701 //______________________________________________________________________________
1702 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, Bool_t submit, const char *jdl)
1703 {
1704 // Static method that checks the status of merging. This can submit merging jobs that did not produced the expected
1705 // output. If <submit> is false (checking) returns true only when the final merged file was found. If submit is true returns
1706 // true if the jobs were successfully submitted.
1707    Int_t countOrig = 0;
1708    Int_t countStage = 0;
1709    Int_t stage = 0;
1710    Int_t i;
1711    Bool_t doneFinal = kFALSE;
1712    TBits chunksDone;
1713    TString saliendir(aliendir);
1714    TString sfilename, stmp;
1715    saliendir.ReplaceAll("//","/");
1716    saliendir = saliendir.Strip(TString::kTrailing, '/');
1717    if (!gGrid) {
1718       ::Error("GetNregisteredFiles", "You need to be connected to AliEn.");
1719       return kFALSE;
1720    }
1721    sfilename = filename;
1722    sfilename.ReplaceAll(".root", "*.root");
1723    printf("Checking directory <%s> for merged files <%s> ...\n", aliendir, sfilename.Data());
1724    TString command = Form("find %s/ *%s", saliendir.Data(), sfilename.Data());
1725    TGridResult *res = gGrid->Command(command);
1726    if (!res) {
1727       ::Error("GetNregisteredFiles","Error: No result for the find command\n");
1728       return kFALSE;
1729    }     
1730    TIter nextmap(res);
1731    TMap *map = 0;   
1732    while ((map=(TMap*)nextmap())) {
1733       TString turl = map->GetValue("turl")->GetName();
1734       if (!turl.Length()) {
1735          // Nothing found
1736          delete res;
1737          return kFALSE;
1738       }
1739       turl.ReplaceAll("alien://", "");
1740       turl.ReplaceAll(saliendir, "");
1741       sfilename = gSystem->BaseName(turl);
1742       turl = turl.Strip(TString::kLeading, '/');
1743       // Now check to what the file corresponds to: 
1744       //    original output           - aliendir/%03d/filename
1745       //    merged file (which stage) - aliendir/filename-Stage%02d_%04d
1746       //    final merged file         - aliendir/filename
1747       if (sfilename == turl) {
1748          if (sfilename == filename) {
1749             doneFinal = kTRUE;
1750          } else {   
1751             // check stage
1752             Int_t index = sfilename.Index("Stage");
1753             if (index<0) continue;
1754             stmp = sfilename(index+5,2);
1755             Int_t istage = atoi(stmp);
1756             stmp = sfilename(index+8,4);
1757             Int_t ijob = atoi(stmp);
1758             if (istage<stage) continue; // Ignore lower stages
1759             if (istage>stage) {
1760                countStage = 0;
1761                chunksDone.ResetAllBits();
1762                stage = istage;
1763             }
1764             countStage++;
1765             chunksDone.SetBitNumber(ijob);
1766          }     
1767       } else {
1768          countOrig++;
1769       }
1770       if (doneFinal) {
1771          delete res;
1772          printf("=> Removing files from previous stages...\n");
1773          gGrid->Rm(Form("%s/*Stage*.root", aliendir));
1774          for (i=1; i<stage; i++)
1775             gGrid->Rm(Form("%s/*Stage%d*.zip", aliendir, i));
1776          return kTRUE;
1777       }               
1778    }
1779    delete res;
1780    // Compute number of jobs that were submitted for the current stage
1781    Int_t ntotstage = countOrig;
1782    for (i=1; i<=stage; i++) {
1783       if (ntotstage%nperchunk) ntotstage = (ntotstage/nperchunk)+1;
1784       else                     ntotstage = (ntotstage/nperchunk);
1785    }   
1786    // Now compare with the number of set bits in the chunksDone array
1787    Int_t nmissing = (stage>0)?(ntotstage - countStage):0;
1788    // Print the info
1789    printf("*** Found %d original files\n", countOrig);
1790    if (stage==0) printf("*** No merging completed so far.\n");
1791    else          printf("*** Found %d out of %d files merged for stage %d\n", countStage, ntotstage, stage);
1792    if (nmissing) printf("*** Number of merged files missing for this stage: %d -> check merging job completion\n", nmissing);
1793    if (!submit) return doneFinal;
1794    // Sumbit merging jobs for all missing chunks for the current stage.
1795    TString query = Form("submit %s %s", jdl, aliendir);
1796    Int_t ichunk = -1;
1797    if (nmissing) {
1798       for (i=0; i<nmissing; i++) {
1799          ichunk = chunksDone.FirstNullBit(ichunk+1);
1800          Int_t jobId = SubmitSingleJob(Form("%s %d %d", query.Data(), stage, ichunk));
1801          if (!jobId) return kFALSE;
1802       }
1803       return kTRUE;
1804    }
1805    // Submit next stage of merging
1806    if (stage==0) countStage = countOrig;
1807    Int_t nchunks = (countStage/nperchunk);
1808    if (countStage%nperchunk) nchunks += 1;
1809    for (i=0; i<nchunks; i++) {
1810       Int_t jobId = SubmitSingleJob(Form("%s %d %d", query.Data(), stage+1, i));
1811       if (!jobId) return kFALSE;
1812    }        
1813    return kTRUE;
1814 }      
1815
1816 //______________________________________________________________________________
1817 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
1818 {
1819 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
1820    if (!gGrid) return 0;
1821    printf("=> %s ------> ",query);
1822    TGridResult *res = gGrid->Command(query);
1823    if (!res) return 0;
1824    TString jobId = res->GetKey(0,"jobId");
1825    delete res;
1826    if (jobId.IsNull()) {
1827       printf("submission failed. Reason:\n");
1828       gGrid->Stdout();
1829       gGrid->Stderr();
1830       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
1831       return 0;
1832    }
1833    printf(" Job id: %s\n", jobId.Data());
1834    return atoi(jobId);
1835 }  
1836
1837 //______________________________________________________________________________
1838 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage, Int_t ichunk)
1839 {
1840 // Merge given output files from basedir. The file merger will merge nmaxmerge
1841 // files in a group. Merging can be done in stages:
1842 // stage=0 : will merge all existing files in a single stage
1843 // stage=1 : does a find command for all files that do NOT contain the string "Stage". 
1844 //           If their number is bigger that nmaxmerge, only the files from 
1845 //           ichunk*nmaxmerge to ichunk*(nmaxmerge+1)-1 will get merged as output_stage_<ichunk>
1846 // stage=n : does a find command for files named <output>Stage<stage-1>_*. If their number is bigger than
1847 //           nmaxmerge, merge just the chunk ichunk, otherwise write the merged output to the file 
1848 //           named <output>.
1849    TString outputFile = output;
1850    TString command;
1851    TString outputChunk;
1852    TString previousChunk = "";
1853    Int_t countChunk = 0;
1854    Int_t countZero = nmaxmerge;
1855    Bool_t merged = kTRUE;
1856    Int_t index = outputFile.Index("@");
1857    if (index > 0) outputFile.Remove(index);
1858    TString inputFile = outputFile;
1859    if (stage>1) inputFile.ReplaceAll(".root", Form("-Stage%02d_*.root", stage-1));
1860    command = Form("find %s/ *%s", basedir, inputFile.Data());
1861    printf("command: %s\n", command.Data());
1862    TGridResult *res = gGrid->Command(command);
1863    if (!res) {
1864       ::Error("MergeOutput","No result for the find command\n");
1865       return kFALSE;
1866    }     
1867
1868    TFileMerger *fm = 0;
1869    TIter nextmap(res);
1870    TMap *map = 0;
1871    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
1872    outputChunk = outputFile;
1873    outputChunk.ReplaceAll(".root", "_*.root");
1874    // Check for existent temporary merge files
1875    // Check overwrite mode and remove previous partial results if needed
1876    // Preserve old merging functionality for stage 0.
1877    if (stage==0) {
1878       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
1879          while (1) {
1880             // Skip as many input files as in a chunk
1881             for (Int_t counter=0; counter<nmaxmerge; counter++) map = (TMap*)nextmap();
1882             if (!map) {
1883                ::Error("MergeOutput", "Cannot resume merging for <%s>, nentries=%d", outputFile.Data(), res->GetSize());
1884                delete res;
1885                return kFALSE;
1886             }
1887             outputChunk = outputFile;
1888             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
1889             countChunk++;
1890             if (gSystem->AccessPathName(outputChunk)) continue;
1891             // Merged file with chunks up to <countChunk> found
1892             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
1893             previousChunk = outputChunk;
1894             break;
1895          }
1896       }   
1897       countZero = nmaxmerge;
1898    
1899       while ((map=(TMap*)nextmap())) {
1900       // Loop 'find' results and get next LFN
1901          if (countZero == nmaxmerge) {
1902             // First file in chunk - create file merger and add previous chunk if any.
1903             fm = new TFileMerger(kFALSE);
1904             fm->SetFastMethod(kTRUE);
1905             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
1906             outputChunk = outputFile;
1907             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
1908          }
1909          // If last file found, put merged results in the output file
1910          if (map == res->Last()) outputChunk = outputFile;
1911          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1912          if (!objs || !objs->GetString().Length()) {
1913             // Nothing found - skip this output
1914             delete res;
1915             delete fm;
1916             return kFALSE;
1917          } 
1918          // Add file to be merged and decrement chunk counter.
1919          fm->AddFile(objs->GetString());
1920          countZero--;
1921          if (countZero==0 || map == res->Last()) {            
1922             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1923             // Nothing found - skip this output
1924                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
1925                delete res;
1926                delete fm;
1927                return kFALSE;
1928             }
1929             fm->OutputFile(outputChunk);
1930             // Merge the outputs, then go to next chunk      
1931             if (!fm->Merge()) {
1932                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
1933                delete res;
1934                delete fm;
1935                return kFALSE;
1936             } else {
1937                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
1938                gSystem->Unlink(previousChunk);
1939             }
1940             if (map == res->Last()) {
1941                delete res;
1942                delete fm;
1943                break;
1944             }      
1945             countChunk++;
1946             countZero = nmaxmerge;
1947             previousChunk = outputChunk;
1948          }
1949       }
1950       return merged;
1951    }
1952    // Merging stage different than 0.
1953    // Move to the begining of the requested chunk.
1954    outputChunk = outputFile;
1955    if (nmaxmerge < res->GetSize()) {
1956       if (ichunk*nmaxmerge >= res->GetSize()) {
1957          ::Error("MergeOutput", "Cannot merge merge chunk %d grouping %d files from %d total.", ichunk, nmaxmerge, res->GetSize());
1958          delete res;
1959          return kFALSE;
1960       }   
1961       for (Int_t counter=0; counter<ichunk*nmaxmerge; counter++) map = (TMap*)nextmap();
1962       outputChunk.ReplaceAll(".root", Form("-Stage%02d_%04d.root", stage, ichunk));
1963    }
1964    countZero = nmaxmerge;  
1965    fm = new TFileMerger(kFALSE);
1966    fm->SetFastMethod(kTRUE);
1967    while ((map=(TMap*)nextmap())) {
1968       // Loop 'find' results and get next LFN
1969       TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1970       if (!objs || !objs->GetString().Length()) {
1971          // Nothing found - skip this output
1972          delete res;
1973          delete fm;
1974          return kFALSE;
1975       } 
1976       // Add file to be merged and decrement chunk counter.
1977       fm->AddFile(objs->GetString());
1978       countZero--;
1979       if (countZero==0) break;
1980    }
1981    delete res;
1982    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1983       // Nothing found - skip this output
1984       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
1985       delete fm;
1986       return kFALSE;
1987    }
1988    fm->OutputFile(outputChunk);
1989    // Merge the outputs
1990    if (!fm->Merge()) {
1991       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
1992       delete fm;
1993       return kFALSE;
1994    } else {
1995       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
1996    }
1997    delete fm;
1998    return kTRUE;
1999
2000
2001 //______________________________________________________________________________
2002 Bool_t AliAnalysisAlien::MergeOutputs()
2003 {
2004 // Merge analysis outputs existing in the AliEn space.
2005    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
2006    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2007    if (!Connect()) {
2008       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
2009       return kFALSE;
2010    }
2011    if (fMergeViaJDL) {
2012       if (!TestBit(AliAnalysisGrid::kMerge)) {
2013          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
2014          return kFALSE; 
2015       }     
2016       if (fProductionMode) {
2017          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
2018          return kFALSE;
2019       }
2020       Info("MergeOutputs", "Submitting merging JDL");
2021       if (!SubmitMerging()) return kFALSE;
2022       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
2023       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
2024       return kFALSE;
2025    }   
2026    // Get the output path
2027    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2028    if (!DirectoryExists(fGridOutputDir)) {
2029       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
2030       return kFALSE;
2031    }
2032    if (!fOutputFiles.Length()) {
2033       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2034       return kFALSE;
2035    }
2036    // Check if fast read option was requested
2037    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
2038         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
2039    if (fFastReadOption) {
2040       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
2041              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2042       gEnv->SetValue("XNet.ConnectTimeout",10);
2043       gEnv->SetValue("XNet.RequestTimeout",10);
2044       gEnv->SetValue("XNet.MaxRedirectCount",2);
2045       gEnv->SetValue("XNet.ReconnectTimeout",10);
2046       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
2047    }   
2048    // Make sure we change the temporary directory
2049    gSystem->Setenv("TMPDIR", gSystem->pwd());
2050    TObjArray *list = fOutputFiles.Tokenize(",");
2051    TIter next(list);
2052    TObjString *str;
2053    TString outputFile;
2054    Bool_t merged = kTRUE;
2055    while((str=(TObjString*)next())) {
2056       outputFile = str->GetString();
2057       Int_t index = outputFile.Index("@");
2058       if (index > 0) outputFile.Remove(index);
2059       TString outputChunk = outputFile;
2060       outputChunk.ReplaceAll(".root", "_*.root");
2061       // Skip already merged outputs
2062       if (!gSystem->AccessPathName(outputFile)) {
2063          if (fOverwriteMode) {
2064             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
2065             gSystem->Unlink(outputFile);
2066             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2067                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2068                      outputChunk.Data());
2069                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2070             }
2071          } else {   
2072             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
2073             continue;
2074          }   
2075       } else {
2076          if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2077             Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2078                   outputChunk.Data());
2079             gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2080          }   
2081       }
2082       if (fMergeExcludes.Length() &&
2083           fMergeExcludes.Contains(outputFile.Data())) continue;
2084       // Perform a 'find' command in the output directory, looking for registered outputs    
2085       merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
2086       if (!merged) {
2087          Error("MergeOutputs", "Terminate() will  NOT be executed");
2088          return kFALSE;
2089       }
2090       TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2091       if (fileOpened) fileOpened->Close();
2092    } 
2093    return kTRUE;
2094 }   
2095
2096 //______________________________________________________________________________
2097 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2098 {
2099 // Use the output files connected to output containers from the analysis manager
2100 // rather than the files defined by SetOutputFiles
2101    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
2102       Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
2103    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2104 }
2105       
2106 //______________________________________________________________________________
2107 void AliAnalysisAlien::SetOutputFiles(const char *list)
2108 {
2109 // Manually set the output files list.
2110 // Removes duplicates. Not allowed if default outputs are not disabled.
2111    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2112       Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2113       return;
2114    }
2115    Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2116    fOutputFiles = "";
2117    TString slist = list;
2118    if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2119    TObjArray *arr = slist.Tokenize(" "); 
2120    TObjString *os;
2121    TIter next(arr);
2122    TString sout;
2123    while ((os=(TObjString*)next())) {
2124       sout = os->GetString();
2125       if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2126       if (fOutputFiles.Contains(sout)) continue;
2127       if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2128       fOutputFiles += sout;
2129    }
2130    delete arr;   
2131 }      
2132
2133 //______________________________________________________________________________
2134 void AliAnalysisAlien::SetOutputArchive(const char *list)
2135 {
2136 // Manually set the output archive list. Free text - you are on your own...
2137 // Not allowed if default outputs are not disabled.
2138    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2139       Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2140       return;
2141    }
2142    Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2143    fOutputArchive = list;
2144 }
2145
2146 //______________________________________________________________________________
2147 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2148 {
2149 // Setting a prefered output SE is not allowed anymore.
2150    Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2151 }
2152
2153 //______________________________________________________________________________
2154 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
2155 {
2156 // Start remote grid analysis.
2157    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2158    Bool_t testMode = TestBit(AliAnalysisGrid::kTest);
2159    if (!mgr || !mgr->IsInitialized()) {
2160       Error("StartAnalysis", "You need an initialized analysis manager for this");
2161       return kFALSE;
2162    }
2163    // Are we in PROOF mode ?
2164    if (mgr->IsProofMode()) {
2165       Info("StartAnalysis", "##### Starting PROOF analysis on via the plugin #####");
2166       if (fProofCluster.IsNull()) {
2167          Error("StartAnalysis", "You need to specify the proof cluster name via SetProofCluster");
2168          return kFALSE;
2169       }   
2170       if (fProofDataSet.IsNull() && !testMode) {
2171          Error("StartAnalysis", "You need to specify a dataset using SetProofDataSet()");
2172          return kFALSE;
2173       }   
2174       // Set the needed environment
2175       gEnv->SetValue("XSec.GSI.DelegProxy","2");
2176       // Do we need to reset PROOF ? The success of the Reset operation cannot be checked
2177       if (fProofReset && !testMode) {
2178          if (fProofReset==1) {
2179             Info("StartAnalysis", "Sending soft reset signal to proof cluster %s", fProofCluster.Data());
2180             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kFALSE);", fProofCluster.Data()));
2181          } else {         
2182             Info("StartAnalysis", "Sending hard reset signal to proof cluster %s", fProofCluster.Data());
2183             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kTRUE);", fProofCluster.Data()));
2184          }
2185          Info("StartAnalysis", "Stopping the analysis. Please use SetProofReset(0) to resume.");
2186          return kFALSE;
2187       }
2188       // Do we need to change the ROOT version ? The success of this cannot be checked.
2189       if (!fRootVersionForProof.IsNull() && !testMode) {
2190          gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"%s\");", 
2191                             fProofCluster.Data(), fRootVersionForProof.Data()));
2192       }
2193       // Connect to PROOF and check the status
2194       Long_t proof = 0;
2195       if (!testMode) {
2196          if (fNproofWorkers) 
2197             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"workers=%d\");", fProofCluster.Data(), fNproofWorkers));
2198          else   
2199             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
2200       } else {
2201          proof = gROOT->ProcessLine("TProof::Open(\"\");");
2202          if (!proof) {
2203             Error("StartAnalysis", "Could not start PROOF in test mode");
2204             return kFALSE;
2205          }   
2206       }
2207       if (!proof) {
2208          Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
2209          return kFALSE;
2210       }   
2211       // Is dataset existing ?
2212       if (!testMode) {
2213          TString dataset = fProofDataSet;
2214          Int_t index = dataset.Index("#");
2215          if (index>=0) dataset.Remove(index);
2216 //         if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
2217 //            Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
2218 //            return kFALSE;
2219 //         }
2220 //         Info("StartAnalysis", "Dataset %s found", dataset.Data());
2221       }
2222       // Is ClearPackages() needed ?
2223       if (TestSpecialBit(kClearPackages)) {
2224          Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
2225          gROOT->ProcessLine("gProof->ClearPackages();");
2226       }
2227       // Is a given aliroot mode requested ?
2228       TList optionsList;
2229       if (!fAliRootMode.IsNull()) {
2230          TString alirootMode = fAliRootMode;
2231          if (alirootMode == "default") alirootMode = "";
2232          Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
2233          optionsList.SetOwner();
2234          optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
2235          // Check the additional libs to be loaded
2236          TString extraLibs;
2237          if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:ANALYSISalice";
2238          // Parse the extra libs for .so
2239          if (fAdditionalLibs.Length()) {
2240             TObjArray *list = fAdditionalLibs.Tokenize(" ");
2241             TIter next(list);
2242             TObjString *str;
2243             while((str=(TObjString*)next()) && str->GetString().Contains(".so")) {
2244                TString stmp = str->GetName();
2245                if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
2246                stmp.ReplaceAll(".so","");
2247                if (!extraLibs.IsNull()) extraLibs += ":";
2248                extraLibs += stmp;
2249             }
2250             if (list) delete list;            
2251          }
2252          if (!extraLibs.IsNull()) optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
2253          // Check extra includes
2254          if (!fIncludePath.IsNull()) {
2255             TString includePath = fIncludePath;
2256             includePath.ReplaceAll(" ",":");
2257             includePath.Strip(TString::kTrailing, ':');
2258             Info("StartAnalysis", "Adding extra includes: %s",includePath.Data()); 
2259             optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
2260          }
2261          // Enable AliRoot par
2262          if (testMode) {
2263          // Enable proof lite package
2264             TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
2265             for (Int_t i=0; i<optionsList.GetSize(); i++) {
2266                TNamed *obj = (TNamed*)optionsList.At(i);
2267                printf("%s  %s\n", obj->GetName(), obj->GetTitle());
2268             }   
2269             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
2270               && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)0x%lx);",alirootLite.Data(),(ULong_t)&optionsList))) {
2271                   Info("StartAnalysis", "AliRootProofLite enabled");
2272             } else {                      
2273                Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
2274                return kFALSE;
2275             }   
2276          } else {
2277             if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)0x%lx);", 
2278                                    fAliROOTVersion.Data(), (ULong_t)&optionsList))) {
2279                Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
2280                return kFALSE;
2281             }         
2282          }      
2283       } else {
2284          if (fAdditionalLibs.Contains(".so") && !testMode) {
2285             Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
2286                    \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
2287             return kFALSE;       
2288          }
2289       }
2290       // Enable par files if requested
2291       if (fPackages && fPackages->GetEntries()) {
2292          TIter next(fPackages);
2293          TObject *package;
2294          while ((package=next())) {
2295             if (gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2296                if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\");", package->GetName()))) {
2297                   Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2298                   return kFALSE;
2299                }
2300             } else {
2301                Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2302                return kFALSE;
2303             }
2304          }
2305       }
2306       // Do we need to load analysis source files ?
2307       // NOTE: don't load on client since this is anyway done by the user to attach his task.
2308       if (fAnalysisSource.Length()) {
2309          TObjArray *list = fAnalysisSource.Tokenize(" ");
2310          TIter next(list);
2311          TObjString *str;
2312          while((str=(TObjString*)next())) {
2313             gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
2314          }   
2315          if (list) delete list;
2316       }
2317       if (testMode) {
2318       // Register dataset to proof lite.
2319          if (fFileForTestMode.IsNull()) {
2320             Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2321             return kFALSE;
2322          }
2323          if (gSystem->AccessPathName(fFileForTestMode)) {
2324             Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2325             return kFALSE;
2326          }   
2327          TFileCollection *coll = new TFileCollection();
2328          coll->AddFromFile(fFileForTestMode);
2329          gROOT->ProcessLine("if (gProof->ExistsDataSet(\"test_collection\")) gProof->RemoveDataSet(\"test_collection\");");
2330          gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)0x%lx);", (ULong_t)coll));
2331          gROOT->ProcessLine("gProof->VerifyDataSet(\"test_collection\");");
2332          gROOT->ProcessLine("gProof->ShowDataSets();");
2333          
2334       }
2335       return kTRUE;
2336    }
2337    
2338    // Check if output files have to be taken from the analysis manager
2339    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2340       fOutputFiles = "";
2341       TIter next(mgr->GetOutputs());
2342       AliAnalysisDataContainer *output;
2343       while ((output=(AliAnalysisDataContainer*)next())) {
2344          const char *filename = output->GetFileName();
2345          if (!(strcmp(filename, "default"))) {
2346             if (!mgr->GetOutputEventHandler()) continue;
2347             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
2348          }
2349          if (fOutputFiles.Contains(filename)) continue;
2350          if (fOutputFiles.Length()) fOutputFiles += ",";
2351          fOutputFiles += filename;
2352       }
2353       // Add extra files registered to the analysis manager
2354       if (mgr->GetExtraFiles().Length()) {
2355          if (fOutputFiles.Length()) fOutputFiles += ",";
2356          TString extra = mgr->GetExtraFiles();
2357          extra.ReplaceAll(" ", ",");
2358          // Protection in case extra files do not exist (will it work?)
2359          extra.ReplaceAll(".root", "*.root");
2360          fOutputFiles += extra;
2361       }
2362       // Compose the output archive.
2363       fOutputArchive = "log_archive.zip:std*@disk=1 ";
2364       fOutputArchive += Form("root_archive.zip:%s@disk=%d",fOutputFiles.Data(),fNreplicas);
2365    }
2366 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
2367    if (TestBit(AliAnalysisGrid::kOffline)) {
2368       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2369       \n                         there nor any job run. You can revise the JDL and analysis \
2370       \n                         macro then run the same in \"submit\" mode.");
2371    } else if (TestBit(AliAnalysisGrid::kTest)) {
2372       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
2373       \n                         dataset.");
2374    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2375       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
2376       \n                         space and job submitted.");
2377    } else if (TestBit(AliAnalysisGrid::kMerge)) {
2378       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
2379       if (fMergeViaJDL) CheckInputData();
2380       return kTRUE;
2381    } else {
2382       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
2383    }   
2384       
2385    Print();   
2386    if (!Connect()) {
2387       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
2388       return kFALSE;
2389    }
2390    if (IsCheckCopy()) CheckFileCopy(gGrid->GetHomeDirectory());
2391    if (!CheckInputData()) {
2392       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
2393       return kFALSE;
2394    }   
2395    if (!CreateDataset(fDataPattern)) {
2396       TString serror;
2397       if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2398       if (fRunNumbers.Length()) serror = "run numbers";
2399       if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2400       serror += Form("\n   or data pattern <%s>", fDataPattern.Data());
2401       Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2402       return kFALSE;
2403    }   
2404    WriteAnalysisFile();   
2405    WriteAnalysisMacro();
2406    WriteExecutable();
2407    WriteValidationScript();
2408    if (fMergeViaJDL) {
2409       WriteMergingMacro();
2410       WriteMergeExecutable();
2411       WriteValidationScript(kTRUE);
2412    }   
2413    if (!CreateJDL()) return kFALSE;
2414    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2415    if (testMode) {
2416       // Locally testing the analysis
2417       Info("StartAnalysis", "\n_______________________________________________________________________ \
2418       \n   Running analysis script in a daughter shell as on a worker node \
2419       \n_______________________________________________________________________");
2420       TObjArray *list = fOutputFiles.Tokenize(",");
2421       TIter next(list);
2422       TObjString *str;
2423       TString outputFile;
2424       while((str=(TObjString*)next())) {
2425          outputFile = str->GetString();
2426          Int_t index = outputFile.Index("@");
2427          if (index > 0) outputFile.Remove(index);         
2428          if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
2429       }
2430       delete list;
2431       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
2432       TString validationScript = fExecutable;
2433       validationScript.ReplaceAll(".sh", "_validation.sh");
2434       gSystem->Exec(Form("bash %s",validationScript.Data()));
2435 //      gSystem->Exec("cat stdout");
2436       return kFALSE;
2437    }
2438    // Check if submitting is managed by LPM manager
2439    if (fProductionMode) {
2440       TString prodfile = fJDLName;
2441       prodfile.ReplaceAll(".jdl", ".prod");
2442       WriteProductionFile(prodfile);
2443       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2444       return kFALSE;
2445    }   
2446    // Submit AliEn job(s)
2447    gGrid->Cd(fGridOutputDir);
2448    TGridResult *res;
2449    TString jobID = "";
2450    if (!fRunNumbers.Length() && !fRunRange[0]) {
2451       // Submit a given xml or a set of runs
2452       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
2453       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
2454       if (res) {
2455          const char *cjobId = res->GetKey(0,"jobId");
2456          if (!cjobId) {
2457             gGrid->Stdout();
2458             gGrid->Stderr();
2459             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
2460             return kFALSE;
2461          } else {
2462             Info("StartAnalysis", "\n_______________________________________________________________________ \
2463             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2464             \n_______________________________________________________________________",
2465                    fJDLName.Data(), cjobId);
2466             jobID = cjobId;      
2467          }          
2468          delete res;
2469       } else {
2470          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2471          return kFALSE;      
2472       }   
2473    } else {
2474       // Submit for a range of enumeration of runs.
2475       if (!Submit()) return kFALSE;
2476    }   
2477          
2478    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2479    \n You may exit at any time and terminate the job later using the option <terminate> \
2480    \n ##################################################################################", jobID.Data());
2481    gSystem->Exec("aliensh");
2482    return kTRUE;
2483 }
2484
2485 //______________________________________________________________________________
2486 Bool_t AliAnalysisAlien::Submit()
2487 {
2488 // Submit all master jobs.
2489    Int_t nmasterjobs = fInputFiles->GetEntries();
2490    Long_t tshoot = gSystem->Now();
2491    if (!fNsubmitted && !SubmitNext()) return kFALSE;
2492    while (fNsubmitted < nmasterjobs) {
2493       Long_t now = gSystem->Now();
2494       if ((now-tshoot)>30000) {
2495          tshoot = now;
2496          if (!SubmitNext()) return kFALSE;
2497       }   
2498    }
2499    return kTRUE;
2500 }
2501
2502 //______________________________________________________________________________
2503 Bool_t AliAnalysisAlien::SubmitMerging()
2504 {
2505 // Submit all merging jobs.
2506    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2507    gGrid->Cd(fGridOutputDir);
2508    TString mergeJDLName = fExecutable;
2509    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2510    Int_t ntosubmit = fInputFiles->GetEntries();
2511    for (Int_t i=0; i<ntosubmit; i++) {
2512       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2513       runOutDir.ReplaceAll(".xml", "");
2514       if (fOutputToRunNo) {
2515          // The output directory is the run number
2516          printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
2517          runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
2518       } else {
2519          // The output directory is the master number in 3 digits format
2520          printf("### Submitting merging job for master <%03d>\n", i);
2521          runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
2522       }
2523       // Check now the number of merging stages.
2524       TObjArray *list = fOutputFiles.Tokenize(",");
2525       TIter next(list);
2526       TObjString *str;
2527       TString outputFile;
2528       while((str=(TObjString*)next())) {
2529          outputFile = str->GetString();
2530          Int_t index = outputFile.Index("@");
2531          if (index > 0) outputFile.Remove(index);
2532          if (!fMergeExcludes.Contains(outputFile)) break;
2533       }
2534       delete list;
2535       Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, kTRUE, mergeJDLName);
2536       if (!done) return kFALSE;
2537    }
2538    if (!ntosubmit) return kTRUE;
2539    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
2540    \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
2541    \n ##################################################################################");
2542    gSystem->Exec("aliensh");
2543    return kTRUE;
2544 }
2545
2546 //______________________________________________________________________________
2547 Bool_t AliAnalysisAlien::SubmitNext()
2548 {
2549 // Submit next bunch of master jobs if the queue is free. The first master job is
2550 // submitted right away, while the next will not be unless the previous was split.
2551 // The plugin will not submit new master jobs if there are more that 500 jobs in
2552 // waiting phase.
2553    static Bool_t iscalled = kFALSE;
2554    static Int_t firstmaster = 0;
2555    static Int_t lastmaster = 0;
2556    static Int_t npermaster  = 0;
2557    if (iscalled) return kTRUE;
2558    iscalled = kTRUE;
2559    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2560    Int_t ntosubmit = 0;
2561    TGridResult *res;
2562    TString jobID = "";
2563    Int_t nmasterjobs = fInputFiles->GetEntries();
2564    if (!fNsubmitted) {
2565       ntosubmit = 1;
2566       if (!IsUseSubmitPolicy()) {
2567          if (ntosubmit>5)
2568             Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
2569                 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
2570          ntosubmit = nmasterjobs;
2571       }   
2572    } else {
2573       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
2574       printf("=== master %d: %s\n", lastmaster, status.Data());
2575       // If last master not split, just return
2576       if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
2577       // No more than 100 waiting jobs
2578       if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
2579       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
2580       if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
2581       if (!ntosubmit) ntosubmit = 1;
2582       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
2583              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2584    }
2585    for (Int_t i=0; i<ntosubmit; i++) {
2586       // Submit for a range of enumeration of runs.
2587       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
2588       TString query;
2589       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2590       runOutDir.ReplaceAll(".xml", "");
2591       if (fOutputToRunNo)
2592          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2593       else
2594          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
2595       printf("********* %s\n",query.Data());
2596       res = gGrid->Command(query);
2597       if (res) {
2598          TString cjobId1 = res->GetKey(0,"jobId");
2599          if (!cjobId1.Length()) {
2600             iscalled = kFALSE;
2601             gGrid->Stdout();
2602             gGrid->Stderr();
2603             Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2604             return kFALSE;
2605          } else {
2606             Info("StartAnalysis", "\n_______________________________________________________________________ \
2607             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2608             \n_______________________________________________________________________",
2609                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
2610             jobID += cjobId1;
2611             jobID += " ";
2612             lastmaster = cjobId1.Atoi();
2613             if (!firstmaster) firstmaster = lastmaster;
2614             fNsubmitted++;
2615          }          
2616          delete res;
2617       } else {
2618          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2619          return kFALSE;
2620       }   
2621    }
2622    iscalled = kFALSE;
2623    return kTRUE;
2624 }
2625
2626 //______________________________________________________________________________
2627 void AliAnalysisAlien::WriteAnalysisFile()
2628 {
2629 // Write current analysis manager into the file <analysisFile>
2630    TString analysisFile = fExecutable;
2631    analysisFile.ReplaceAll(".sh", ".root");
2632    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2633       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2634       if (!mgr || !mgr->IsInitialized()) {
2635          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2636          return;
2637       }
2638       // Check analysis type
2639       TObject *handler;
2640       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
2641       handler = (TObject*)mgr->GetInputEventHandler();
2642       if (handler) {
2643          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
2644          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
2645       }
2646       TDirectory *cdir = gDirectory;
2647       TFile *file = TFile::Open(analysisFile, "RECREATE");
2648       if (file) {
2649          // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
2650          if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
2651          // Unless merging makes no sense
2652          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
2653          mgr->Write();
2654          delete file;
2655          // Enable termination for local jobs
2656          mgr->SetSkipTerminate(kFALSE);
2657       }
2658       if (cdir) cdir->cd();
2659       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
2660    }   
2661    Bool_t copy = kTRUE;
2662    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2663    if (copy) {
2664       CdWork();
2665       TString workdir = gGrid->GetHomeDirectory();
2666       workdir += fGridWorkingDir;
2667       Info("CreateJDL", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
2668       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
2669       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
2670    }   
2671 }
2672
2673 //______________________________________________________________________________
2674 void AliAnalysisAlien::WriteAnalysisMacro()
2675 {
2676 // Write the analysis macro that will steer the analysis in grid mode.
2677    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2678       ofstream out;
2679       out.open(fAnalysisMacro.Data(), ios::out);
2680       if (!out.good()) {
2681          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2682          return;
2683       }
2684       Bool_t hasSTEERBase = kFALSE;
2685       Bool_t hasESD = kFALSE;
2686       Bool_t hasAOD = kFALSE;
2687       Bool_t hasANALYSIS = kFALSE;
2688       Bool_t hasANALYSISalice = kFALSE;
2689       Bool_t hasCORRFW = kFALSE;
2690       TString func = fAnalysisMacro;
2691       TString type = "ESD";
2692       TString comment = "// Analysis using ";
2693       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2694       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2695          type = "AOD";
2696          comment += "AOD";
2697       }   
2698       if (type!="AOD" && fFriendChainName!="") {
2699          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2700          return;
2701       }
2702       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2703       else comment += " data";
2704       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2705       func.ReplaceAll(".C", "");
2706       out << "void " << func.Data() << "()" << endl; 
2707       out << "{" << endl;
2708       out << comment.Data() << endl;
2709       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2710       out << "   TStopwatch timer;" << endl;
2711       out << "   timer.Start();" << endl << endl;
2712       // Change temp directory to current one
2713       out << "// Set temporary merging directory to current one" << endl;
2714       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
2715       out << "// load base root libraries" << endl;
2716       out << "   gSystem->Load(\"libTree\");" << endl;
2717       out << "   gSystem->Load(\"libGeom\");" << endl;
2718       out << "   gSystem->Load(\"libVMC\");" << endl;
2719       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2720       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2721       if (fAdditionalRootLibs.Length()) {
2722          // in principle libtree /lib geom libvmc etc. can go into this list, too
2723          out << "// Add aditional libraries" << endl;
2724          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2725          TIter next(list);
2726          TObjString *str;
2727          while((str=(TObjString*)next())) {
2728             if (str->GetString().Contains(".so"))
2729             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2730          }
2731          if (list) delete list;
2732       }
2733       out << "// include path" << endl;
2734       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2735       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2736       out << "// Load analysis framework libraries" << endl;
2737       TString setupPar = "AliAnalysisAlien::SetupPar";
2738       if (!fPackages) {
2739          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2740          out << "   gSystem->Load(\"libESD\");" << endl;
2741          out << "   gSystem->Load(\"libAOD\");" << endl;
2742          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2743          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2744          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2745       } else {
2746          TIter next(fPackages);
2747          TObject *obj;
2748          TString pkgname;
2749          while ((obj=next())) {
2750             pkgname = obj->GetName();
2751             if (pkgname == "STEERBase" ||
2752                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2753             if (pkgname == "ESD" ||
2754                 pkgname == "ESD.par")       hasESD = kTRUE;
2755             if (pkgname == "AOD" ||
2756                 pkgname == "AOD.par")       hasAOD = kTRUE;
2757             if (pkgname == "ANALYSIS" ||
2758                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2759             if (pkgname == "ANALYSISalice" ||
2760                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2761             if (pkgname == "CORRFW" ||
2762                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2763          }
2764          if (hasANALYSISalice) setupPar = "SetupPar";   
2765          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2766          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2767          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2768          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2769          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2770          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2771          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2772          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2773          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2774          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2775          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2776          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2777          out << "// Compile other par packages" << endl;
2778          next.Reset();
2779          while ((obj=next())) {
2780             pkgname = obj->GetName();
2781             if (pkgname == "STEERBase" ||
2782                 pkgname == "STEERBase.par" ||
2783                 pkgname == "ESD" ||
2784                 pkgname == "ESD.par" ||
2785                 pkgname == "AOD" ||
2786                 pkgname == "AOD.par" ||
2787                 pkgname == "ANALYSIS" ||
2788                 pkgname == "ANALYSIS.par" ||
2789                 pkgname == "ANALYSISalice" ||
2790                 pkgname == "ANALYSISalice.par" ||
2791                 pkgname == "CORRFW" ||
2792                 pkgname == "CORRFW.par") continue;
2793             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2794          }   
2795       }   
2796       if (fAdditionalLibs.Length()) {
2797          out << "// Add aditional AliRoot libraries" << endl;
2798          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2799          TIter next(list);
2800          TObjString *str;
2801          while((str=(TObjString*)next())) {
2802             if (str->GetString().Contains(".so"))
2803                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2804             if (str->GetString().Contains(".par"))
2805                out << "   if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
2806          }
2807          if (list) delete list;
2808       }
2809       out << endl;
2810       out << "// analysis source to be compiled at runtime (if any)" << endl;
2811       if (fAnalysisSource.Length()) {
2812          TObjArray *list = fAnalysisSource.Tokenize(" ");
2813          TIter next(list);
2814          TObjString *str;
2815          while((str=(TObjString*)next())) {
2816             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2817          }   
2818          if (list) delete list;
2819       }
2820       out << endl;
2821       if (fFastReadOption) {
2822          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 !!! \
2823                 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2824          out << "// fast xrootd reading enabled" << endl;
2825          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2826          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2827          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
2828          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2829          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
2830          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2831       }   
2832       out << "// connect to AliEn and make the chain" << endl;
2833       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2834       if (IsUsingTags()) {
2835          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2836       } else {
2837          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;   
2838       }   
2839       out << "// read the analysis manager from file" << endl;
2840       TString analysisFile = fExecutable;
2841       analysisFile.ReplaceAll(".sh", ".root");
2842       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2843       out << "   if (!file) return;" << endl; 
2844       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
2845       out << "   AliAnalysisManager *mgr = 0;" << endl;
2846       out << "   TKey *key;" << endl;
2847       out << "   while ((key=(TKey*)nextkey())) {" << endl;
2848       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2849       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2850       out << "   };" << endl;
2851       out << "   if (!mgr) {" << endl;
2852       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file " << analysisFile <<"\");" << endl;
2853       out << "      return;" << endl;
2854       out << "   }" << endl << endl;
2855       out << "   mgr->PrintStatus();" << endl;
2856       if (AliAnalysisManager::GetAnalysisManager()) {
2857          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2858             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2859          } else {
2860             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2861          }
2862       }   
2863       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
2864       out << "   timer.Stop();" << endl;
2865       out << "   timer.Print();" << endl;
2866       out << "}" << endl << endl;
2867       if (IsUsingTags()) {
2868          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2869          out << "{" << endl;
2870          out << "// Create a chain using tags from the xml file." << endl;
2871          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2872          out << "   if (!coll) {" << endl;
2873          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2874          out << "      return NULL;" << endl;
2875          out << "   }" << endl;
2876          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2877          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2878          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
2879          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
2880          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
2881          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2882          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
2883          out << "   // Check if the cuts configuration file was provided" << endl;
2884          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2885          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2886          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2887          out << "   }" << endl;
2888          if (fFriendChainName=="") {
2889             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2890          } else {
2891             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
2892             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2893             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2894          }
2895          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2896          out << "   chain->ls();" << endl;
2897          out << "   return chain;" << endl;
2898          out << "}" << endl << endl;
2899          if (gSystem->AccessPathName("ConfigureCuts.C")) {
2900             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
2901             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2902             msg += "                      AliLHCTagCuts *lhcCuts,\n";
2903             msg += "                      AliDetectorTagCuts *detCuts,\n";
2904             msg += "                      AliEventTagCuts *evCuts)";
2905             Info("WriteAnalysisMacro", "%s", msg.Data());
2906          }
2907       } 
2908       if (!IsUsingTags() || fFriendChainName!="") {
2909          out <<"//________________________________________________________________________________" << endl;
2910          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2911          out << "{" << endl;
2912          out << "// Create a chain using url's from xml file" << endl;
2913          out << "   TString treename = type;" << endl;
2914          out << "   treename.ToLower();" << endl;
2915          out << "   treename += \"Tree\";" << endl;
2916          out << "   printf(\"***************************************\\n\");" << endl;
2917          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
2918          out << "   printf(\"***************************************\\n\");" << endl;
2919          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2920          out << "   if (!coll) {" << endl;
2921          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2922          out << "      return NULL;" << endl;
2923          out << "   }" << endl;
2924          out << "   TChain *chain = new TChain(treename);" << endl;
2925          if(fFriendChainName!="") {
2926             out << "   TChain *chainFriend = new TChain(treename);" << endl;
2927          }
2928          out << "   coll->Reset();" << endl;
2929          out << "   while (coll->Next()) {" << endl;
2930          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
2931          if(fFriendChainName!="") {
2932             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
2933             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2934             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2935             out << "      chainFriend->Add(fileFriend.Data());" << endl;
2936          }
2937          out << "   }" << endl;
2938          out << "   if (!chain->GetNtrees()) {" << endl;
2939          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2940          out << "      return NULL;" << endl;
2941          out << "   }" << endl;
2942          if(fFriendChainName!="") {
2943             out << "   chain->AddFriend(chainFriend);" << endl;
2944          }
2945          out << "   return chain;" << endl;
2946          out << "}" << endl << endl;
2947       }   
2948       if (hasANALYSISalice) {
2949          out <<"//________________________________________________________________________________" << endl;
2950          out << "Bool_t SetupPar(const char *package) {" << endl;
2951          out << "// Compile the package and set it up." << endl;
2952          out << "   TString pkgdir = package;" << endl;
2953          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2954          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2955          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2956          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2957          out << "   // Check for BUILD.sh and execute" << endl;
2958          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2959          out << "      printf(\"*******************************\\n\");" << endl;
2960          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2961          out << "      printf(\"*******************************\\n\");" << endl;
2962          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2963          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2964          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2965          out << "         return kFALSE;" << endl;
2966          out << "      }" << endl;
2967          out << "   } else {" << endl;
2968          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2969          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2970          out << "      return kFALSE;" << endl;
2971          out << "   }" << endl;
2972          out << "   // Check for SETUP.C and execute" << endl;
2973          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2974          out << "      printf(\"*******************************\\n\");" << endl;
2975          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2976          out << "      printf(\"*******************************\\n\");" << endl;
2977          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2978          out << "   } else {" << endl;
2979          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2980          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2981          out << "      return kFALSE;" << endl;
2982          out << "   }" << endl;
2983          out << "   // Restore original workdir" << endl;
2984          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2985          out << "   return kTRUE;" << endl;
2986          out << "}" << endl;
2987       }
2988       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2989    }   
2990    Bool_t copy = kTRUE;
2991    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2992    if (copy) {
2993       CdWork();
2994       TString workdir = gGrid->GetHomeDirectory();
2995       workdir += fGridWorkingDir;
2996       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2997       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2998          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2999          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
3000          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
3001       }   
3002       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
3003       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
3004    }
3005 }
3006
3007 //______________________________________________________________________________
3008 void AliAnalysisAlien::WriteMergingMacro()
3009 {
3010 // Write a macro to merge the outputs per master job.
3011    if (!fMergeViaJDL) return;
3012    if (!fOutputFiles.Length()) {
3013       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3014       return;
3015    }   
3016    TString mergingMacro = fExecutable;
3017    mergingMacro.ReplaceAll(".sh","_merge.C");
3018    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3019    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3020       ofstream out;
3021       out.open(mergingMacro.Data(), ios::out);
3022       if (!out.good()) {
3023          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3024          return;
3025       }
3026       Bool_t hasSTEERBase = kFALSE;
3027       Bool_t hasESD = kFALSE;
3028       Bool_t hasAOD = kFALSE;
3029       Bool_t hasANALYSIS = kFALSE;
3030       Bool_t hasANALYSISalice = kFALSE;
3031       Bool_t hasCORRFW = kFALSE;
3032       TString func = mergingMacro;
3033       TString comment;
3034       func.ReplaceAll(".C", "");
3035       out << "void " << func.Data() << "(const char *dir, Int_t stage=0, Int_t ichunk=0)" << endl;
3036       out << "{" << endl;
3037       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
3038       out << "   TStopwatch timer;" << endl;
3039       out << "   timer.Start();" << endl << endl;
3040       if (!fExecutableCommand.Contains("aliroot")) {
3041          out << "// load base root libraries" << endl;
3042          out << "   gSystem->Load(\"libTree\");" << endl;
3043          out << "   gSystem->Load(\"libGeom\");" << endl;
3044          out << "   gSystem->Load(\"libVMC\");" << endl;
3045          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
3046          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
3047       }   
3048       if (fAdditionalRootLibs.Length()) {
3049          // in principle libtree /lib geom libvmc etc. can go into this list, too
3050          out << "// Add aditional libraries" << endl;
3051          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3052          TIter next(list);
3053          TObjString *str;
3054          while((str=(TObjString*)next())) {
3055             if (str->GetString().Contains(".so"))
3056             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3057          }
3058          if (list) delete list;
3059       }
3060       out << "// include path" << endl;
3061       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3062       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
3063       out << "// Load analysis framework libraries" << endl;
3064       if (!fPackages) {
3065          if (!fExecutableCommand.Contains("aliroot")) {
3066             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3067             out << "   gSystem->Load(\"libESD\");" << endl;
3068             out << "   gSystem->Load(\"libAOD\");" << endl;
3069          }
3070          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3071          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3072          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3073       } else {
3074          TIter next(fPackages);
3075          TObject *obj;
3076          TString pkgname;
3077          TString setupPar = "AliAnalysisAlien::SetupPar";
3078          while ((obj=next())) {
3079             pkgname = obj->GetName();
3080             if (pkgname == "STEERBase" ||
3081                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3082             if (pkgname == "ESD" ||
3083                 pkgname == "ESD.par")       hasESD = kTRUE;
3084             if (pkgname == "AOD" ||