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