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