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