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