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