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