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