Added loop for extraction of clusters really attached to its track.
[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                   fAliRootMode(),
135                   fProofProcessOpt(),
136                   fMergeDirName(),
137                   fInputFiles(0),
138                   fPackages(0),
139                   fModules(0),
140                   fProofParam(),
141                   fDropToShell(true),
142                   fGridJobIDs(""),
143                   fGridStages(""),
144                   fFriendLibs(""),
145                   fTreeName()
146 {
147 // Dummy ctor.
148    SetDefaults();
149 }
150
151 //______________________________________________________________________________
152 AliAnalysisAlien::AliAnalysisAlien(const char *name)
153                  :AliAnalysisGrid(name),
154                   fGridJDL(NULL),
155                   fMergingJDL(NULL),
156                   fPrice(0),
157                   fTTL(0),
158                   fSplitMaxInputFileNumber(0),
159                   fMaxInitFailed(0),
160                   fMasterResubmitThreshold(0),
161                   fNtestFiles(0),
162                   fNrunsPerMaster(0),
163                   fMaxMergeFiles(0),
164                   fMaxMergeStages(0),
165                   fNsubmitted(0),
166                   fProductionMode(0),
167                   fOutputToRunNo(0),
168                   fMergeViaJDL(0),
169                   fFastReadOption(0),
170                   fOverwriteMode(1),
171                   fNreplicas(2),
172                   fNproofWorkers(0),
173                   fNproofWorkersPerSlave(0),
174                   fProofReset(0),
175                   fRunNumbers(),
176                   fExecutable(),
177                   fExecutableCommand(),
178                   fArguments(),
179                   fExecutableArgs(),
180                   fAnalysisMacro(),
181                   fAnalysisSource(),
182                   fValidationScript(),
183                   fAdditionalRootLibs(),
184                   fAdditionalLibs(),
185                   fSplitMode(),
186                   fAPIVersion(),
187                   fROOTVersion(),
188                   fAliROOTVersion(),
189                   fExternalPackages(),
190                   fUser(),
191                   fGridWorkingDir(),
192                   fGridDataDir(),
193                   fDataPattern(),
194                   fGridOutputDir(),
195                   fOutputArchive(),
196                   fOutputFiles(),
197                   fInputFormat(),
198                   fDatasetName(),
199                   fJDLName(),
200                   fTerminateFiles(),
201                   fMergeExcludes(),
202                   fRegisterExcludes(),
203                   fIncludePath(),
204                   fCloseSE(),
205                   fFriendChainName(),
206                   fJobTag(),
207                   fOutputSingle(),
208                   fRunPrefix(),
209                   fProofCluster(),
210                   fProofDataSet(),
211                   fFileForTestMode(),
212                   fAliRootMode(),
213                   fProofProcessOpt(),
214                   fMergeDirName(),
215                   fInputFiles(0),
216                   fPackages(0),
217                   fModules(0),
218                   fProofParam(),
219                   fDropToShell(true),
220                   fGridJobIDs(""),
221                   fGridStages(""),
222                   fFriendLibs(""),
223                   fTreeName()
224 {
225 // Default ctor.
226    SetDefaults();
227 }
228
229 //______________________________________________________________________________
230 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
231                  :AliAnalysisGrid(other),
232                   fGridJDL(NULL),
233                   fMergingJDL(NULL),
234                   fPrice(other.fPrice),
235                   fTTL(other.fTTL),
236                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
237                   fMaxInitFailed(other.fMaxInitFailed),
238                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
239                   fNtestFiles(other.fNtestFiles),
240                   fNrunsPerMaster(other.fNrunsPerMaster),
241                   fMaxMergeFiles(other.fMaxMergeFiles),
242                   fMaxMergeStages(other.fMaxMergeStages),
243                   fNsubmitted(other.fNsubmitted),
244                   fProductionMode(other.fProductionMode),
245                   fOutputToRunNo(other.fOutputToRunNo),
246                   fMergeViaJDL(other.fMergeViaJDL),
247                   fFastReadOption(other.fFastReadOption),
248                   fOverwriteMode(other.fOverwriteMode),
249                   fNreplicas(other.fNreplicas),
250                   fNproofWorkers(other.fNproofWorkers),
251                   fNproofWorkersPerSlave(other.fNproofWorkersPerSlave),
252                   fProofReset(other.fProofReset),
253                   fRunNumbers(other.fRunNumbers),
254                   fExecutable(other.fExecutable),
255                   fExecutableCommand(other.fExecutableCommand),
256                   fArguments(other.fArguments),
257                   fExecutableArgs(other.fExecutableArgs),
258                   fAnalysisMacro(other.fAnalysisMacro),
259                   fAnalysisSource(other.fAnalysisSource),
260                   fValidationScript(other.fValidationScript),
261                   fAdditionalRootLibs(other.fAdditionalRootLibs),
262                   fAdditionalLibs(other.fAdditionalLibs),
263                   fSplitMode(other.fSplitMode),
264                   fAPIVersion(other.fAPIVersion),
265                   fROOTVersion(other.fROOTVersion),
266                   fAliROOTVersion(other.fAliROOTVersion),
267                   fExternalPackages(other.fExternalPackages),
268                   fUser(other.fUser),
269                   fGridWorkingDir(other.fGridWorkingDir),
270                   fGridDataDir(other.fGridDataDir),
271                   fDataPattern(other.fDataPattern),
272                   fGridOutputDir(other.fGridOutputDir),
273                   fOutputArchive(other.fOutputArchive),
274                   fOutputFiles(other.fOutputFiles),
275                   fInputFormat(other.fInputFormat),
276                   fDatasetName(other.fDatasetName),
277                   fJDLName(other.fJDLName),
278                   fTerminateFiles(other.fTerminateFiles),
279                   fMergeExcludes(other.fMergeExcludes),
280                   fRegisterExcludes(other.fRegisterExcludes),
281                   fIncludePath(other.fIncludePath),
282                   fCloseSE(other.fCloseSE),
283                   fFriendChainName(other.fFriendChainName),
284                   fJobTag(other.fJobTag),
285                   fOutputSingle(other.fOutputSingle),
286                   fRunPrefix(other.fRunPrefix),
287                   fProofCluster(other.fProofCluster),
288                   fProofDataSet(other.fProofDataSet),
289                   fFileForTestMode(other.fFileForTestMode),
290                   fAliRootMode(other.fAliRootMode),
291                   fProofProcessOpt(other.fProofProcessOpt),
292                   fMergeDirName(other.fMergeDirName),
293                   fInputFiles(0),
294                   fPackages(0),
295                   fModules(0),
296                   fProofParam(),
297                   fDropToShell(other.fDropToShell),
298                   fGridJobIDs(other.fGridJobIDs),
299                   fGridStages(other.fGridStages),
300                   fFriendLibs(other.fFriendLibs),
301                   fTreeName(other.fTreeName)
302 {
303 // Copy ctor.
304    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
305    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
306    fRunRange[0] = other.fRunRange[0];
307    fRunRange[1] = other.fRunRange[1];
308    if (other.fInputFiles) {
309       fInputFiles = new TObjArray();
310       TIter next(other.fInputFiles);
311       TObject *obj;
312       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
313       fInputFiles->SetOwner();
314    }   
315    if (other.fPackages) {
316       fPackages = new TObjArray();
317       TIter next(other.fPackages);
318       TObject *obj;
319       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
320       fPackages->SetOwner();
321    }   
322    if (other.fModules) {
323       fModules = new TObjArray();
324       fModules->SetOwner();
325       TIter next(other.fModules);
326       AliAnalysisTaskCfg *mod, *crt;
327       while ((crt=(AliAnalysisTaskCfg*)next())) {
328          mod = new AliAnalysisTaskCfg(*crt);
329          fModules->Add(mod);
330       }
331    }   
332 }
333
334 //______________________________________________________________________________
335 AliAnalysisAlien::~AliAnalysisAlien()
336 {
337 // Destructor.
338    delete fGridJDL;
339    delete fMergingJDL;
340    delete fInputFiles;
341    delete fPackages;
342    delete fModules;
343    fProofParam.DeleteAll();
344 }   
345
346 //______________________________________________________________________________
347 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
348 {
349 // Assignment.
350    if (this != &other) {
351       AliAnalysisGrid::operator=(other);
352       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
353       fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
354       fPrice                   = other.fPrice;
355       fTTL                     = other.fTTL;
356       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
357       fMaxInitFailed           = other.fMaxInitFailed;
358       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
359       fNtestFiles              = other.fNtestFiles;
360       fNrunsPerMaster          = other.fNrunsPerMaster;
361       fMaxMergeFiles           = other.fMaxMergeFiles;
362       fMaxMergeStages          = other.fMaxMergeStages;
363       fNsubmitted              = other.fNsubmitted;
364       fProductionMode          = other.fProductionMode;
365       fOutputToRunNo           = other.fOutputToRunNo;
366       fMergeViaJDL             = other.fMergeViaJDL;
367       fFastReadOption          = other.fFastReadOption;
368       fOverwriteMode           = other.fOverwriteMode;
369       fNreplicas               = other.fNreplicas;
370       fNproofWorkers           = other.fNproofWorkers;
371       fNproofWorkersPerSlave   = other.fNproofWorkersPerSlave;
372       fProofReset              = other.fProofReset;
373       fRunNumbers              = other.fRunNumbers;
374       fExecutable              = other.fExecutable;
375       fExecutableCommand       = other.fExecutableCommand;
376       fArguments               = other.fArguments;
377       fExecutableArgs          = other.fExecutableArgs;
378       fAnalysisMacro           = other.fAnalysisMacro;
379       fAnalysisSource          = other.fAnalysisSource;
380       fValidationScript        = other.fValidationScript;
381       fAdditionalRootLibs      = other.fAdditionalRootLibs;
382       fAdditionalLibs          = other.fAdditionalLibs;
383       fSplitMode               = other.fSplitMode;
384       fAPIVersion              = other.fAPIVersion;
385       fROOTVersion             = other.fROOTVersion;
386       fAliROOTVersion          = other.fAliROOTVersion;
387       fExternalPackages        = other.fExternalPackages;
388       fUser                    = other.fUser;
389       fGridWorkingDir          = other.fGridWorkingDir;
390       fGridDataDir             = other.fGridDataDir;
391       fDataPattern             = other.fDataPattern;
392       fGridOutputDir           = other.fGridOutputDir;
393       fOutputArchive           = other.fOutputArchive;
394       fOutputFiles             = other.fOutputFiles;
395       fInputFormat             = other.fInputFormat;
396       fDatasetName             = other.fDatasetName;
397       fJDLName                 = other.fJDLName;
398       fTerminateFiles          = other.fTerminateFiles;
399       fMergeExcludes           = other.fMergeExcludes;
400       fRegisterExcludes        = other.fRegisterExcludes;
401       fIncludePath             = other.fIncludePath;
402       fCloseSE                 = other.fCloseSE;
403       fFriendChainName         = other.fFriendChainName;
404       fJobTag                  = other.fJobTag;
405       fOutputSingle            = other.fOutputSingle;
406       fRunPrefix               = other.fRunPrefix;
407       fProofCluster            = other.fProofCluster;
408       fProofDataSet            = other.fProofDataSet;
409       fFileForTestMode         = other.fFileForTestMode;
410       fAliRootMode             = other.fAliRootMode;
411       fProofProcessOpt         = other.fProofProcessOpt;
412       fMergeDirName            = other.fMergeDirName;
413       fDropToShell             = other.fDropToShell;
414       fGridJobIDs              = other.fGridJobIDs;
415       fGridStages              = other.fGridStages;
416       fFriendLibs              = other.fFriendLibs;
417       fTreeName                = other.fTreeName;
418       if (other.fInputFiles) {
419          fInputFiles = new TObjArray();
420          TIter next(other.fInputFiles);
421          TObject *obj;
422          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
423          fInputFiles->SetOwner();
424       }   
425       if (other.fPackages) {
426          fPackages = new TObjArray();
427          TIter next(other.fPackages);
428          TObject *obj;
429          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
430          fPackages->SetOwner();
431       }   
432       if (other.fModules) {
433          fModules = new TObjArray();
434          fModules->SetOwner();
435          TIter next(other.fModules);
436          AliAnalysisTaskCfg *mod, *crt;
437          while ((crt=(AliAnalysisTaskCfg*)next())) {
438             mod = new AliAnalysisTaskCfg(*crt);
439             fModules->Add(mod);
440          }
441       }   
442    }
443    return *this;
444 }
445
446 //______________________________________________________________________________
447 void AliAnalysisAlien::AddAdditionalLibrary(const char *name)
448 {
449 // Add a single additional library to be loaded. Extension must be present.
450    TString lib(name);
451    if (!lib.Contains(".")) {
452       Error("AddAdditionalLibrary", "Extension not defined for %s", name);
453       return;
454    }
455    if (fAdditionalLibs.Contains(name)) {
456       Warning("AddAdditionalLibrary", "Library %s already added.", name);
457       return;
458    }
459    if (!fAdditionalLibs.IsNull()) fAdditionalLibs += " ";
460    fAdditionalLibs += lib;
461 }   
462
463 //______________________________________________________________________________
464 void AliAnalysisAlien::AddModule(AliAnalysisTaskCfg *module)
465 {
466 // Adding a module. Checks if already existing. Becomes owned by this.
467    if (!module) return;
468    if (GetModule(module->GetName())) {
469       Error("AddModule", "A module having the same name %s already added", module->GetName());
470       return;
471    }
472    if (!fModules) {
473       fModules = new TObjArray();
474       fModules->SetOwner();
475    }
476    fModules->Add(module);
477 }
478
479 //______________________________________________________________________________
480 void AliAnalysisAlien::AddModules(TObjArray *list)
481 {
482 // Adding a list of modules. Checks if already existing. Becomes owned by this.
483    TIter next(list);
484    AliAnalysisTaskCfg *module;
485    while ((module = (AliAnalysisTaskCfg*)next())) AddModule(module);
486 }   
487
488 //______________________________________________________________________________
489 Bool_t AliAnalysisAlien::CheckDependencies()
490 {
491 // Check if all dependencies are satisfied. Reorder modules if needed.
492    Int_t nmodules = GetNmodules();
493    if (!nmodules) {
494       Warning("CheckDependencies", "No modules added yet to check their dependencies");
495       return kTRUE;
496    }   
497    AliAnalysisTaskCfg *mod = 0;
498    AliAnalysisTaskCfg *dep = 0;
499    TString depname;
500    Int_t i, j, k;
501    for (i=0; i<nmodules; i++) {
502       mod = (AliAnalysisTaskCfg*) fModules->At(i);
503       Int_t ndeps = mod->GetNdeps();
504       Int_t istart = i;
505       for (j=0; j<ndeps; j++) {
506          depname = mod->GetDependency(j);
507          dep = GetModule(depname);
508          if (!dep) {
509             Error("CheckDependencies","Dependency %s not added for module %s",
510                    depname.Data(), mod->GetName());
511             return kFALSE;
512          }
513          if (dep->NeedsDependency(mod->GetName())) {
514             Error("CheckDependencies","Modules %s and %s circularly depend on each other",
515                    mod->GetName(), dep->GetName());
516             return kFALSE;
517          }                  
518          Int_t idep = fModules->IndexOf(dep);
519          // The dependency task must come first
520          if (idep>i) {
521             // Remove at idep and move all objects below up one slot
522             // down to index i included.
523             fModules->RemoveAt(idep);
524             for (k=idep-1; k>=i; k--) fModules->AddAt(fModules->RemoveAt(k),k+1);
525             fModules->AddAt(dep, i++);
526          }
527          //Redo from istart if dependencies were inserted
528          if (i>istart) i=istart-1;
529       }
530    }
531    return kTRUE;
532 }      
533
534 //______________________________________________________________________________
535 AliAnalysisManager *AliAnalysisAlien::CreateAnalysisManager(const char *name, const char *filename)
536 {
537 // Create the analysis manager and optionally execute the macro in filename.
538    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
539    if (mgr) return mgr;
540    mgr = new AliAnalysisManager(name);
541    mgr->SetGridHandler((AliAnalysisGrid*)this);
542    if (strlen(filename)) {
543       TString line = gSystem->ExpandPathName(filename);
544       line.Prepend(".x ");
545       gROOT->ProcessLine(line.Data());
546    }
547    return mgr;
548 }      
549       
550 //______________________________________________________________________________
551 Int_t AliAnalysisAlien::GetNmodules() const
552 {
553 // Get number of modules.
554    if (!fModules) return 0;
555    return fModules->GetEntries();
556 }
557
558 //______________________________________________________________________________
559 AliAnalysisTaskCfg *AliAnalysisAlien::GetModule(const char *name)
560 {
561 // Get a module by name.
562    if (!fModules) return 0;
563    return (AliAnalysisTaskCfg*)fModules->FindObject(name);
564 }
565    
566 //______________________________________________________________________________
567 Bool_t AliAnalysisAlien::LoadModule(AliAnalysisTaskCfg *mod)
568 {
569 // Load a given module.
570    if (mod->IsLoaded()) return kTRUE;
571    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
572    if (!mgr) {
573       Error("LoadModule", "No analysis manager created yet. Use CreateAnalysisManager first.");
574       return kFALSE;
575    }   
576    Int_t ndeps = mod->GetNdeps();
577    TString depname;
578    for (Int_t j=0; j<ndeps; j++) {
579       depname = mod->GetDependency(j);
580       AliAnalysisTaskCfg *dep = GetModule(depname);
581       if (!dep) {
582          Error("LoadModule","Dependency %s not existing for module %s",
583                 depname.Data(), mod->GetName());
584          return kFALSE;
585       }
586       if (!LoadModule(dep)) {
587          Error("LoadModule","Dependency %s for module %s could not be loaded",
588                 depname.Data(), mod->GetName());
589          return kFALSE;
590       }
591    }
592    // Load libraries for the module
593    if (!mod->CheckLoadLibraries()) {
594       Error("LoadModule", "Cannot load all libraries for module %s", mod->GetName());
595       return kFALSE;
596    }
597    // Check if a custom file name was requested
598    if (strlen(mod->GetOutputFileName())) mgr->SetCommonFileName(mod->GetOutputFileName());
599
600    // Check if a custom terminate file name was requested
601    if (strlen(mod->GetTerminateFileName())) {
602       if (!fTerminateFiles.IsNull()) fTerminateFiles += ",";
603       fTerminateFiles += mod->GetTerminateFileName();
604    }   
605
606    // Execute the macro
607    if (mod->ExecuteMacro()<0) {
608       Error("LoadModule", "Executing the macro %s with arguments: %s for module %s returned a negative value",
609              mod->GetMacroName(), mod->GetMacroArgs(), mod->GetName());
610       return kFALSE;
611    }
612    // Configure dependencies
613    if (mod->GetConfigMacro() && mod->ExecuteConfigMacro()<0) {
614       Error("LoadModule", "There was an error executing the deps config macro %s for module %s",
615             mod->GetConfigMacro()->GetTitle(), mod->GetName());
616       return kFALSE;
617    }
618    // Adjust extra libraries
619    Int_t nlibs = mod->GetNlibs();
620    TString lib;
621    for (Int_t i=0; i<nlibs; i++) {
622       lib = mod->GetLibrary(i);
623       lib = Form("lib%s.so", lib.Data());
624       if (fAdditionalLibs.Contains(lib)) continue;
625       if (!fAdditionalLibs.IsNull()) fAdditionalLibs += " ";
626       fAdditionalLibs += lib;
627    }
628    return kTRUE;
629 }
630
631 //______________________________________________________________________________
632 Bool_t AliAnalysisAlien::GenerateTrain(const char *name)
633 {
634 // Generate the full train.
635    fAdditionalLibs = "";
636    if (!LoadModules()) return kFALSE;
637    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
638    if (!mgr->InitAnalysis()) return kFALSE;
639    mgr->RunLocalInit();
640    mgr->PrintStatus();
641    Int_t productionMode = fProductionMode;
642    SetProductionMode();
643    TString macro = fAnalysisMacro;
644    TString executable = fExecutable;
645    TString validation = fValidationScript;
646    TString execCommand = fExecutableCommand;
647    SetAnalysisMacro(Form("%s.C", name));
648    SetExecutable(Form("%s.sh", name));
649 //   SetExecutableCommand("aliroot -b -q ");
650    SetValidationScript(Form("%s_validation.sh", name));
651    StartAnalysis();
652    SetProductionMode(productionMode);
653    fAnalysisMacro = macro;
654    fExecutable = executable;
655    fExecutableCommand = execCommand;
656    fValidationScript = validation;
657    return kTRUE;   
658 }   
659
660 //______________________________________________________________________________
661 Bool_t AliAnalysisAlien::GenerateTest(const char *name, const char *modname)
662 {
663 // Generate test macros for a single module or for the full train.
664    fAdditionalLibs = "";
665    if (strlen(modname)) {
666       if (!CheckDependencies()) return kFALSE;
667       AliAnalysisTaskCfg *mod = GetModule(modname);
668       if (!mod) {
669          Error("GenerateTest", "cannot generate test for inexistent module %s", modname);
670          return kFALSE;
671       }
672       if (!LoadModule(mod)) return kFALSE;
673       if (!LoadFriendLibs()) return kFALSE;
674    } else if (!LoadModules()) return kFALSE;
675    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
676    if (!mgr->InitAnalysis()) return kFALSE;
677    mgr->RunLocalInit();
678    mgr->PrintStatus();
679    SetLocalTest(kTRUE);
680    Int_t productionMode = fProductionMode;
681    SetProductionMode();
682    TString macro = fAnalysisMacro;
683    TString executable = fExecutable;
684    TString validation = fValidationScript;
685    TString execCommand = fExecutableCommand;
686    SetAnalysisMacro(Form("%s.C", name));
687    SetExecutable(Form("%s.sh", name));
688       fOutputFiles = GetListOfFiles("outaod");
689       // Add extra files registered to the analysis manager
690       TString extra = GetListOfFiles("ext");
691       if (!extra.IsNull()) {
692          extra.ReplaceAll(".root", "*.root");
693          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
694          fOutputFiles += extra;
695       }
696 //   SetExecutableCommand("aliroot -b -q ");
697    SetValidationScript(Form("%s_validation.sh", name));
698    WriteAnalysisFile();   
699    WriteAnalysisMacro();
700    WriteExecutable();
701    WriteValidationScript();   
702    WriteMergingMacro();
703    WriteMergeExecutable();
704    WriteValidationScript(kTRUE);
705    SetLocalTest(kFALSE);
706    SetProductionMode(productionMode);
707    fAnalysisMacro = macro;
708    fExecutable = executable;
709    fExecutableCommand = execCommand;
710    fValidationScript = validation;
711    return kTRUE;   
712 }
713
714 //______________________________________________________________________________
715 Bool_t AliAnalysisAlien::LoadModules()
716 {
717 // Load all modules by executing the AddTask macros. Checks first the dependencies.
718    fAdditionalLibs = "";
719    Int_t nmodules = GetNmodules();
720    if (!nmodules) {
721       Warning("LoadModules", "No module to be loaded");
722       return kTRUE;
723    }   
724    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
725    if (!mgr) {
726       Error("LoadModules", "No analysis manager created yet. Use CreateAnalysisManager first.");
727       return kFALSE;
728    }   
729    if (!CheckDependencies()) return kFALSE;
730    nmodules = GetNmodules();
731    AliAnalysisTaskCfg *mod;
732    for (Int_t imod=0; imod<nmodules; imod++) {
733       mod = (AliAnalysisTaskCfg*)fModules->At(imod);
734       if (!LoadModule(mod)) return kFALSE;
735    }
736    // Load additional friend libraries
737    return LoadFriendLibs();
738 }      
739
740 //______________________________________________________________________________
741 Bool_t AliAnalysisAlien::LoadFriendLibs() const
742 {
743 // Load libraries required for reading friends.
744    if (fFriendLibs.Length()) {
745       TObjArray *list = 0;
746       TString lib;
747       if (fFriendLibs.Contains(",")) list  = fFriendLibs.Tokenize(",");
748       else                           list  = fFriendLibs.Tokenize(" ");
749       for (Int_t ilib=0; ilib<list->GetEntriesFast(); ilib++) {
750          lib = list->At(ilib)->GetName();
751          lib.ReplaceAll(".so","");
752          lib.ReplaceAll(" ","");
753          if (lib.BeginsWith("lib")) lib.Remove(0, 3);
754          lib.Prepend("lib");
755          Int_t loaded = strlen(gSystem->GetLibraries(lib,"",kFALSE));
756          if (!loaded) loaded = gSystem->Load(lib);
757          if (loaded < 0) {
758             Error("LoadModules", "Cannot load library for friends %s", lib.Data());
759             return kFALSE;
760          }
761       }
762       delete list;
763    }
764    return kTRUE;
765 }   
766
767 //______________________________________________________________________________
768 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
769 {
770 // Set the run number format. Can be a prefix or a format like "%09d"
771    fRunPrefix = prefix;
772    if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
773 }   
774
775 //______________________________________________________________________________
776 void AliAnalysisAlien::AddIncludePath(const char *path)
777 {
778 // Add include path in the remote analysis macro.
779    TString p(path);
780    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
781    else                  fIncludePath += Form("-I%s ", path);
782 }
783
784 //______________________________________________________________________________
785 void AliAnalysisAlien::AddRunNumber(Int_t run)
786 {
787 // Add a run number to the list of runs to be processed.
788    if (fRunNumbers.Length()) fRunNumbers += " ";
789    fRunNumbers += Form(fRunPrefix.Data(), run);
790 }   
791
792 //______________________________________________________________________________
793 void AliAnalysisAlien::AddRunList(const char* runList)
794 {
795 // Add several runs into the list of runs; they are expected to be separated by a blank character.  
796   TString    sList = runList;
797   TObjArray *list  = sList.Tokenize(" ");
798   Int_t n = list->GetEntries();
799   for (Int_t i = 0; i < n; i++) {
800     TObjString *os = (TObjString*)list->At(i);
801     AddRunNumber(os->GetString().Atoi());
802   }
803   delete list;
804 }
805
806 //______________________________________________________________________________
807 void AliAnalysisAlien::AddRunNumber(const char* run)
808 {
809 // Add a run number to the list of runs to be processed.
810    TString runs = run;
811    TObjString *os;
812    TObjArray *arr = runs.Tokenize(" ");
813    TIter next(arr);
814    TString prefix; 
815    prefix.Append(fRunPrefix, fRunPrefix.Index("%d"));
816    while ((os=(TObjString*)next())){
817        if (fRunNumbers.Length()) fRunNumbers += " ";
818        fRunNumbers += Form("%s%s", prefix.Data(), os->GetString().Data());
819    }
820    delete arr;
821 }   
822
823 //______________________________________________________________________________
824 void AliAnalysisAlien::AddDataFile(const char *lfn)
825 {
826 // Adds a data file to the input to be analysed. The file should be a valid LFN
827 // or point to an existing file in the alien workdir.
828    if (!fInputFiles) fInputFiles = new TObjArray();
829    fInputFiles->Add(new TObjString(lfn));
830 }
831
832 //______________________________________________________________________________
833 void AliAnalysisAlien::AddExternalPackage(const char *package)
834 {
835 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
836    if (fExternalPackages) fExternalPackages += " ";
837    fExternalPackages += package;
838 }   
839       
840 //______________________________________________________________________________
841 Bool_t AliAnalysisAlien::Connect()
842 {
843 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
844    if (gGrid && gGrid->IsConnected()) return kTRUE;
845    if (fProductionMode) return kTRUE;
846    if (!gGrid) {
847       Info("Connect", "Trying to connect to AliEn ...");
848       TGrid::Connect("alien://");
849    }
850    if (!gGrid || !gGrid->IsConnected()) {
851       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
852       return kFALSE;
853    }  
854    fUser = gGrid->GetUser();
855    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
856    return kTRUE;
857 }
858
859 //______________________________________________________________________________
860 void AliAnalysisAlien::CdWork()
861 {
862 // Check validity of alien workspace. Create directory if possible.
863    if (!Connect()) {
864       Error("CdWork", "Alien connection required");
865       return;
866    } 
867    TString homedir = gGrid->GetHomeDirectory();
868    TString workdir = homedir + fGridWorkingDir;
869    if (DirectoryExists(workdir)) {
870       gGrid->Cd(workdir);
871       return;
872    }   
873    // Work directory not existing - create it
874    gGrid->Cd(homedir);
875    if (gGrid->Mkdir(workdir, "-p")) {
876       gGrid->Cd(fGridWorkingDir);
877       Info("CdWork", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
878    } else {
879       Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
880               workdir.Data(), homedir.Data());
881       fGridWorkingDir = "";
882    }          
883 }
884
885 //______________________________________________________________________________
886 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
887 {
888 // Check if file copying is possible.
889    if (fProductionMode) return kTRUE;
890    TString salienpath(alienpath);
891    if (salienpath.Contains(" ")) {
892       Error("CheckFileCopy", "path: <%s> contains blancs - FIX IT !",alienpath);
893       return kFALSE;
894    }   
895    if (!Connect()) {
896       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
897       return kFALSE;
898    }
899    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
900         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
901    // Check if alien_CLOSE_SE is defined
902    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
903    if (!closeSE.IsNull()) {
904       Info("CheckFileCopy", "Your current close storage is pointing to: \
905            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
906    } else {
907       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
908    }        
909    // Check if grid directory exists.
910    if (!DirectoryExists(alienpath)) {
911       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
912       return kFALSE;
913    }
914    TString stest = "plugin_test_copy";
915    TFile f(stest, "RECREATE");
916    // User may not have write permissions to current directory 
917    if (f.IsZombie()) {
918       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
919             gSystem->WorkingDirectory());
920       return kFALSE;
921    }
922    f.Close();
923    if (FileExists(Form("alien://%s/%s",alienpath, stest.Data()))) gGrid->Rm(Form("alien://%s/%s",alienpath, stest.Data()));
924    if (!TFile::Cp(stest.Data(), Form("alien://%s/%s",alienpath, stest.Data()))) {
925       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
926            \n# 1. Make sure you have write permissions there. If this is the case: \
927            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
928            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
929            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
930            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
931       gSystem->Unlink(stest.Data());
932       return kFALSE;
933    }   
934    gSystem->Unlink(stest.Data());
935    gGrid->Rm(Form("%s/%s",alienpath,stest.Data()));
936    Info("CheckFileCopy", "### ...SUCCESS ###");
937    return kTRUE;
938 }   
939
940 //______________________________________________________________________________
941 Bool_t AliAnalysisAlien::CheckInputData()
942 {
943 // Check validity of input data. If necessary, create xml files.
944    if (fProductionMode) return kTRUE;
945    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
946       if (!fGridDataDir.Length()) {
947          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
948          return kFALSE;
949       }
950       if (fMergeViaJDL) {
951          Error("CheckInputData", "Merging via jdl works only with run numbers, run range or provided xml");
952          return kFALSE;
953       }   
954       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
955       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
956          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
957       return kTRUE;
958    }
959    // Process declared files
960    Bool_t isCollection = kFALSE;
961    Bool_t isXml = kFALSE;
962    Bool_t useTags = kFALSE;
963    Bool_t checked = kFALSE;
964    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
965    TString file;
966    TString workdir = gGrid->GetHomeDirectory();
967    workdir += fGridWorkingDir;
968    if (fInputFiles) {
969       TObjString *objstr;
970       TIter next(fInputFiles);
971       while ((objstr=(TObjString*)next())) {
972          file = workdir;
973          file += "/";
974          file += objstr->GetString();
975          // Store full lfn path
976          if (FileExists(file)) objstr->SetString(file);
977          else {
978             file = objstr->GetName();
979             if (!FileExists(objstr->GetName())) {
980                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
981                      objstr->GetName(), workdir.Data());
982                return kFALSE;
983             }         
984          }
985          Bool_t iscoll, isxml, usetags;
986          CheckDataType(file, iscoll, isxml, usetags);
987          if (!checked) {
988             checked = kTRUE;
989             isCollection = iscoll;
990             isXml = isxml;
991             useTags = usetags;
992             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
993          } else {
994             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
995                Error("CheckInputData", "Some conflict was found in the types of inputs");
996                return kFALSE;
997             } 
998          }
999       }
1000    }
1001    // Process requested run numbers
1002    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
1003    // Check validity of alien data directory
1004    if (!fGridDataDir.Length()) {
1005       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
1006       return kFALSE;
1007    }
1008    if (!DirectoryExists(fGridDataDir)) {
1009       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
1010       return kFALSE;
1011    }
1012    if (isCollection) {
1013       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
1014       return kFALSE;   
1015    }
1016    
1017    if (checked && !isXml) {
1018       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
1019       return kFALSE;   
1020    }
1021    // Check validity of run number(s)
1022    TObjArray *arr;
1023    TObjString *os;
1024    TString format;
1025    Int_t nruns = 0;
1026    TString schunk, schunk2;
1027    TString path;
1028    if (!checked) {
1029       checked = kTRUE;
1030       useTags = fDataPattern.Contains("tag");
1031       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1032    }   
1033    if (useTags != fDataPattern.Contains("tag")) {
1034       Error("CheckInputData", "Cannot mix input files using/not using tags");
1035       return kFALSE;
1036    }
1037    if (fRunNumbers.Length()) {
1038       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
1039       arr = fRunNumbers.Tokenize(" ");
1040       TIter next(arr);
1041       while ((os=(TObjString*)next())) {
1042          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
1043          if (!DirectoryExists(path)) {
1044             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
1045             continue;
1046          }
1047          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
1048          TString msg = "\n#####   file: ";
1049          msg += path;
1050          msg += " type: xml_collection;";
1051          if (useTags) msg += " using_tags: Yes";
1052          else          msg += " using_tags: No";
1053          Info("CheckDataType", "%s", msg.Data());
1054          if (fNrunsPerMaster<2) {
1055             AddDataFile(Form("%s.xml", os->GetString().Data()));
1056          } else {
1057             nruns++;
1058             if (((nruns-1)%fNrunsPerMaster) == 0) {
1059                schunk = os->GetString();
1060             }   
1061             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
1062             schunk += Form("_%s.xml", os->GetString().Data());
1063             AddDataFile(schunk);
1064          }   
1065       }
1066       delete arr;   
1067    } else {
1068       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
1069       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1070          format = Form("%%s/%s ", fRunPrefix.Data());
1071          path = Form(format.Data(), fGridDataDir.Data(), irun);
1072          if (!DirectoryExists(path)) {
1073             continue;
1074          }
1075          format = Form("%%s/%s.xml", fRunPrefix.Data());
1076          path = Form(format.Data(), workdir.Data(),irun);
1077          TString msg = "\n#####   file: ";
1078          msg += path;
1079          msg += " type: xml_collection;";
1080          if (useTags) msg += " using_tags: Yes";
1081          else          msg += " using_tags: No";
1082          Info("CheckDataType", "%s", msg.Data());
1083          if (fNrunsPerMaster<2) {
1084             format = Form("%s.xml", fRunPrefix.Data());
1085             AddDataFile(Form(format.Data(),irun));
1086          } else {
1087             nruns++;
1088             if (((nruns-1)%fNrunsPerMaster) == 0) {
1089                schunk = Form(fRunPrefix.Data(),irun);
1090             }
1091             format = Form("_%s.xml", fRunPrefix.Data());
1092             schunk2 = Form(format.Data(), irun);
1093             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
1094             schunk += schunk2;
1095             AddDataFile(schunk);
1096          }   
1097       }
1098       if (!fInputFiles) {
1099          schunk += schunk2;
1100          AddDataFile(schunk);
1101       }   
1102    }
1103    return kTRUE;      
1104 }   
1105
1106 //______________________________________________________________________________
1107 Int_t AliAnalysisAlien::CopyLocalDataset(const char *griddir, const char *pattern, Int_t nfiles, const char *output, const char *archivefile, const char *outputdir)
1108 {
1109 // Copy data from the given grid directory according a pattern and make a local
1110 // dataset.
1111 // 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
1112    if (!Connect()) {
1113       Error("CopyLocalDataset", "Cannot copy local dataset with no grid connection");
1114       return 0;
1115    }
1116    if (!DirectoryExists(griddir)) {
1117       Error("CopyLocalDataset", "Data directory %s not existing.", griddir);
1118       return 0;
1119    }
1120    TString command = Form("find -z -l %d %s %s", nfiles, griddir, pattern);
1121    printf("Running command: %s\n", command.Data());
1122    TGridResult *res = gGrid->Command(command);
1123    Int_t nfound = res->GetEntries();
1124    if (!nfound) {
1125       Error("CopyLocalDataset", "No file found in <%s> having pattern <%s>", griddir, pattern);
1126       return 0;
1127    }
1128    printf("... found %d files. Copying locally ...\n", nfound);
1129    
1130    // archives
1131    TObjArray* additionalArchives = 0;
1132    if (strlen(archivefile) > 0 && TString(archivefile).Contains(";")) {
1133       additionalArchives = TString(archivefile).Tokenize(";");
1134       archivefile = additionalArchives->At(0)->GetName();
1135       additionalArchives->RemoveAt(0);
1136       additionalArchives->Compress();
1137    }
1138    
1139    // Copy files locally
1140    ofstream out;
1141    out.open(output, ios::out);
1142    TMap *map;
1143    TString turl, dirname, filename, temp;
1144    TString cdir = gSystem->WorkingDirectory();
1145    gSystem->MakeDirectory(outputdir);
1146    gSystem->ChangeDirectory(outputdir);
1147    Int_t ncopied = 0;
1148    for (Int_t i=0; i<nfound; i++) {
1149       map = (TMap*)res->At(i);
1150       turl = map->GetValue("turl")->GetName();
1151       filename = gSystem->BaseName(turl.Data());
1152       dirname = gSystem->DirName(turl.Data());
1153       dirname = gSystem->BaseName(dirname.Data());
1154       gSystem->MakeDirectory(dirname);
1155       
1156       TString source(turl);
1157       TString targetFileName(filename);
1158       
1159       if (strlen(archivefile) > 0) {
1160 // TODO here the archive in which the file resides should be determined
1161 // however whereis returns only a guid, and guid2lfn does not work
1162 // Therefore we use the one provided as argument for now
1163          source = Form("%s/%s", gSystem->DirName(source.Data()), archivefile);
1164          targetFileName = archivefile;
1165       }
1166       if (TFile::Cp(source, Form("file:./%s/%s", dirname.Data(), targetFileName.Data()))) {
1167          Bool_t success = kTRUE;
1168          if (additionalArchives) {
1169             for (Int_t j=0; j<additionalArchives->GetEntriesFast(); j++) {
1170                TString target;
1171                target.Form("./%s/%s", dirname.Data(), additionalArchives->At(j)->GetName());
1172                gSystem->MakeDirectory(gSystem->DirName(target));
1173                success &= TFile::Cp(Form("%s/%s", gSystem->DirName(source.Data()), additionalArchives->At(j)->GetName()), Form("file:%s", target.Data()));
1174             }
1175          }
1176
1177          if (success) {
1178             if (strlen(archivefile) > 0) targetFileName = Form("%s#%s", targetFileName.Data(), gSystem->BaseName(turl.Data()));
1179             out << cdir << Form("/%s/%s/%s", outputdir, dirname.Data(), targetFileName.Data()) << endl;
1180             ncopied++;
1181          }
1182       }
1183    }
1184    gSystem->ChangeDirectory(cdir);
1185    delete res;
1186    delete additionalArchives;
1187    return ncopied;
1188 }   
1189
1190 //______________________________________________________________________________
1191 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
1192 {
1193 // Create dataset for the grid data directory + run number.
1194    const Int_t gMaxEntries = 15000;
1195    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
1196    if (!Connect()) {
1197       Error("CreateDataset", "Cannot create dataset with no grid connection");
1198       return kFALSE;
1199    }   
1200
1201    // Cd workspace
1202    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
1203    TString workdir = gGrid->GetHomeDirectory();
1204    workdir += fGridWorkingDir;
1205
1206    // Compose the 'find' command arguments
1207    TString format;
1208    TString command;
1209    TString delimiter = pattern;
1210    delimiter.Strip();
1211    if (delimiter.Contains(" ")) delimiter = "";
1212    else delimiter = " ";
1213    TString options = "-x collection ";
1214    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
1215    else options += Form("-l %d ", gMaxEntries);  // Protection for the find command
1216    TString conditions = "";
1217    Int_t nstart = 0;
1218    Int_t ncount = 0;
1219    Int_t stage = 0;
1220    TString file;
1221    TString path;
1222    Int_t nruns = 0;
1223    TString schunk, schunk2;
1224    TGridCollection *cbase=0, *cadd=0;
1225    if (!fRunNumbers.Length() && !fRunRange[0]) {
1226       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
1227       // Make a single data collection from data directory.
1228       path = fGridDataDir;
1229       if (!DirectoryExists(path)) {
1230          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
1231          return kFALSE;
1232       } 
1233 //      CdWork();
1234       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1235       else file = Form("%s.xml", gSystem->BaseName(path));
1236       while (1) {
1237          ncount = 0;
1238          stage++;
1239          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1240             command = "find ";
1241             command += Form("%s -o %d ",options.Data(), nstart);
1242             command += path;
1243             command += delimiter;
1244             command += pattern;
1245             command += conditions;
1246             printf("command: %s\n", command.Data());
1247             TGridResult *res = gGrid->Command(command);
1248             if (res) delete res;
1249             // Write standard output to file
1250             gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage, file.Data()));
1251             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1252             Bool_t nullFile = kFALSE;
1253             if (!hasGrep) {
1254                 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1255             } else {
1256                nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1257                if (nullFile) {
1258                   Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
1259                   gSystem->Exec("rm -f __tmp*");
1260                   return kFALSE;
1261                }
1262                TString line;
1263                ifstream in;
1264                in.open("__tmp__");
1265                in >> line;
1266                in.close();
1267                gSystem->Exec("rm -f __tmp__");
1268                ncount = line.Atoi();
1269             }         
1270          }
1271          if (ncount == gMaxEntries) {
1272             Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1273             cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1274             if (!cbase) cbase = cadd;
1275             else {
1276                cbase->Add(cadd);
1277                delete cadd;
1278             }   
1279             nstart += ncount;
1280          } else {
1281             if (cbase) {
1282                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1283                printf("... please wait - TAlienCollection::Add() scales badly...\n");
1284                cbase->Add(cadd);
1285                delete cadd;
1286                cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1287                delete cbase; cbase = 0;               
1288             } else {
1289                TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1290             }
1291             gSystem->Exec("rm -f __tmp*");   
1292             Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1293             break;
1294          }
1295       }
1296       Bool_t fileExists = FileExists(file);
1297       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
1298          // Copy xml file to alien space
1299          if (fileExists) gGrid->Rm(file);
1300          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1301          if (!FileExists(file)) {
1302             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1303             return kFALSE;
1304          }
1305          // Update list of files to be processed.
1306       }
1307       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
1308       return kTRUE;
1309    }   
1310    // Several runs
1311    Bool_t nullResult = kTRUE;
1312    if (fRunNumbers.Length()) {
1313       TObjArray *arr = fRunNumbers.Tokenize(" ");
1314       TObjString *os;
1315       TIter next(arr);
1316       while ((os=(TObjString*)next())) {
1317          nstart = 0;
1318          stage = 0;
1319          path = Form("%s/%s/", fGridDataDir.Data(), os->GetString().Data());
1320          if (!DirectoryExists(path)) continue;
1321 //         CdWork();
1322          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1323          else file = Form("%s.xml", os->GetString().Data());
1324          // If local collection file does not exist, create it via 'find' command.
1325          while (1) {
1326             ncount = 0;
1327             stage++;
1328             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1329                command = "find ";
1330                command +=  Form("%s -o %d ",options.Data(), nstart);
1331                command += path;
1332                command += delimiter;
1333                command += pattern;
1334                command += conditions;
1335                TGridResult *res = gGrid->Command(command);
1336                if (res) delete res;
1337                // Write standard output to file
1338                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1339                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1340                Bool_t nullFile = kFALSE;
1341                if (!hasGrep) {
1342                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1343                } else {
1344                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1345                   if (nullFile) {
1346                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1347                      gSystem->Exec("rm -f __tmp*");
1348                      fRunNumbers.ReplaceAll(os->GetString().Data(), "");
1349                      break;
1350                   }   
1351                   TString line;
1352                   ifstream in;
1353                   in.open("__tmp__");
1354                   in >> line;
1355                   in.close();
1356                   gSystem->Exec("rm -f __tmp__");   
1357                   ncount = line.Atoi();
1358                }
1359                nullResult = kFALSE;         
1360             }
1361             if (ncount == gMaxEntries) {
1362                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1363                if (fNrunsPerMaster > 1) {
1364                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1365                           file.Data(),gMaxEntries);
1366                   return kFALSE;
1367                }           
1368                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1369                if (!cbase) cbase = cadd;
1370                else {
1371                   cbase->Add(cadd);
1372                   delete cadd;
1373                }   
1374                nstart += ncount;
1375             } else {
1376                if (cbase && fNrunsPerMaster<2) {
1377                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1378                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1379                   cbase->Add(cadd);
1380                   delete cadd;
1381                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1382                   delete cbase; cbase = 0;               
1383                } else {
1384                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1385                }
1386                gSystem->Exec("rm -f __tmp*");   
1387                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1388                break;
1389             }
1390          }   
1391          if (TestBit(AliAnalysisGrid::kTest)) break;
1392          // Check if there is one run per master job.
1393          if (fNrunsPerMaster<2) {
1394             if (FileExists(file)) {
1395                if (fOverwriteMode) gGrid->Rm(file);
1396                else {
1397                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1398                   continue;
1399                }   
1400             }        
1401             // Copy xml file to alien space
1402             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1403             if (!FileExists(file)) {
1404                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1405                delete arr;
1406                return kFALSE;
1407             }
1408          } else {
1409             nruns++;
1410             if (((nruns-1)%fNrunsPerMaster) == 0) {
1411                schunk = os->GetString();
1412                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1413             } else {
1414                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1415                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
1416                cbase->Add(cadd);
1417                delete cadd;
1418             }
1419             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
1420                continue;
1421             }   
1422             schunk += Form("_%s.xml", os->GetString().Data());
1423             if (FileExists(schunk)) {               
1424                if (fOverwriteMode) gGrid->Rm(file);
1425                else {
1426                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1427                   continue;
1428                }   
1429             }        
1430             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
1431             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1432             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1433             if (!FileExists(schunk)) {
1434                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1435                delete arr;
1436                return kFALSE;
1437             }
1438          }
1439       }   
1440       delete arr;
1441       if (nullResult) {
1442          Error("CreateDataset", "No valid dataset corresponding to the query!");
1443          return kFALSE;
1444       }
1445    } else {
1446       // Process a full run range.
1447       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1448          format = Form("%%s/%s/", fRunPrefix.Data());
1449          nstart = 0;
1450          stage = 0;
1451          path = Form(format.Data(), fGridDataDir.Data(), irun);
1452          if (!DirectoryExists(path)) continue;
1453 //         CdWork();
1454          format = Form("%s.xml", fRunPrefix.Data());
1455          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1456          else file = Form(format.Data(), irun);
1457          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
1458             if (fOverwriteMode) gGrid->Rm(file);
1459             else {
1460                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1461                continue;
1462             }   
1463          }
1464          // If local collection file does not exist, create it via 'find' command.
1465          while (1) {
1466             ncount = 0;
1467             stage++;
1468             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1469                command = "find ";
1470                command +=  Form("%s -o %d ",options.Data(), nstart);
1471                command += path;
1472                command += delimiter;
1473                command += pattern;
1474                command += conditions;
1475                TGridResult *res = gGrid->Command(command);
1476                if (res) delete res;
1477                // Write standard output to file
1478                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1479                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1480                Bool_t nullFile = kFALSE;
1481                if (!hasGrep) {
1482                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1483                } else {
1484                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1485                   if (nullFile) {
1486                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1487                      gSystem->Exec("rm -f __tmp*");
1488                      break;
1489                   }   
1490                   TString line;
1491                   ifstream in;
1492                   in.open("__tmp__");
1493                   in >> line;
1494                   in.close();
1495                   gSystem->Exec("rm -f __tmp__");   
1496                   ncount = line.Atoi();
1497                }
1498                nullResult = kFALSE;         
1499             }   
1500             if (ncount == gMaxEntries) {
1501                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1502                if (fNrunsPerMaster > 1) {
1503                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1504                           file.Data(),gMaxEntries);
1505                   return kFALSE;
1506                }           
1507                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1508                if (!cbase) cbase = cadd;
1509                else {
1510                   cbase->Add(cadd);
1511                   delete cadd;
1512                }   
1513                nstart += ncount;
1514             } else {
1515                if (cbase && fNrunsPerMaster<2) {
1516                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1517                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1518                   cbase->Add(cadd);
1519                   delete cadd;
1520                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1521                   delete cbase; cbase = 0;               
1522                } else {
1523                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1524                }
1525                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1526                break;
1527             }
1528          }   
1529          if (TestBit(AliAnalysisGrid::kTest)) break;
1530          // Check if there is one run per master job.
1531          if (fNrunsPerMaster<2) {
1532             if (FileExists(file)) {
1533                if (fOverwriteMode) gGrid->Rm(file);
1534                else {
1535                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1536                   continue;
1537                }   
1538             }        
1539             // Copy xml file to alien space
1540             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1541             if (!FileExists(file)) {
1542                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1543                return kFALSE;
1544             }
1545          } else {
1546             nruns++;
1547             // Check if the collection for the chunk exist locally.
1548             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
1549             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
1550                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
1551                else continue;
1552             }   
1553             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
1554             if (((nruns-1)%fNrunsPerMaster) == 0) {
1555                schunk = Form(fRunPrefix.Data(), irun);
1556                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1557             } else {
1558                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1559                cbase->Add(cadd);
1560                delete cadd;
1561             }
1562             format = Form("%%s_%s.xml", fRunPrefix.Data());
1563             schunk2 = Form(format.Data(), schunk.Data(), irun);
1564             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
1565                continue;
1566             }   
1567             schunk = schunk2;
1568             if (FileExists(schunk)) {
1569                if (fOverwriteMode) gGrid->Rm(schunk);
1570                else {
1571                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1572                   continue;
1573                }   
1574             }        
1575             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
1576             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1577             if (FileExists(schunk)) {
1578                if (fOverwriteMode) gGrid->Rm(schunk);
1579                else {
1580                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
1581                   continue;
1582                }   
1583             }   
1584             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1585             if (!FileExists(schunk)) {
1586                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1587                return kFALSE;
1588             }
1589          }   
1590       }
1591       if (nullResult) {
1592          Error("CreateDataset", "No valid dataset corresponding to the query!");
1593          return kFALSE;
1594       }      
1595    }      
1596    return kTRUE;
1597 }
1598
1599 //______________________________________________________________________________
1600 Bool_t AliAnalysisAlien::CreateJDL()
1601 {
1602 // Generate a JDL file according to current settings. The name of the file is 
1603 // specified by fJDLName.
1604    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1605    Bool_t error = kFALSE;
1606    TObjArray *arr = 0;
1607    Bool_t copy = kTRUE;
1608    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1609    Bool_t generate = kTRUE;
1610    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
1611    if (!Connect()) {
1612       Error("CreateJDL", "Alien connection required");
1613       return kFALSE;
1614    }   
1615    // Check validity of alien workspace
1616    TString workdir;
1617    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1618    if (!fProductionMode &&  !TestBit(AliAnalysisGrid::kTest)) CdWork();
1619    workdir += fGridWorkingDir;
1620    if (generate) {
1621       TObjString *os;
1622       if (!fInputFiles) {
1623          Error("CreateJDL()", "Define some input files for your analysis.");
1624          error = kTRUE;
1625       }
1626       // Compose list of input files   
1627       // Check if output files were defined
1628       if (!fOutputFiles.Length()) {
1629          Error("CreateJDL", "You must define at least one output file");
1630          error = kTRUE;
1631       }   
1632       // Check if an output directory was defined and valid
1633       if (!fGridOutputDir.Length()) {
1634          Error("CreateJDL", "You must define AliEn output directory");
1635          error = kTRUE;
1636       } else {
1637          if (!fProductionMode) {
1638             if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1639             if (!DirectoryExists(fGridOutputDir)) {
1640                if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1641                   Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1642                } else {
1643                   Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1644                   // error = kTRUE;
1645                }
1646             } else {
1647                Warning("CreateJDL", "#### Output directory %s exists! If this contains old data, jobs will fail with ERROR_SV !!! ###", fGridOutputDir.Data());
1648             }   
1649             gGrid->Cd(workdir);
1650          }   
1651       }   
1652       // Exit if any error up to now
1653       if (error) return kFALSE;   
1654       // Set JDL fields
1655       if (!fUser.IsNull()) {
1656          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1657          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1658       }   
1659       fGridJDL->SetExecutable(fExecutable, "This is the startup script");
1660       TString mergeExec = fExecutable;
1661       mergeExec.ReplaceAll(".sh", "_merge.sh");
1662       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1663       mergeExec.ReplaceAll(".sh", ".C");
1664       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
1665       if (!fArguments.IsNull())
1666          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1667       if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1668       else {
1669          if (fProductionMode)  fMergingJDL->SetArguments("wn.xml $4");    // xml, stage
1670          else                  fMergingJDL->SetArguments("wn.xml $2");    // xml, stage
1671      }               
1672
1673       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1674       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1675       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1676       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1677         
1678       if (fMaxInitFailed > 0) {
1679          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1680          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1681       }   
1682       if (fSplitMaxInputFileNumber > 0) {
1683          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1684          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1685       }
1686       if (!IsOneStageMerging()) {
1687          fMergingJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"",fMaxMergeFiles));
1688          fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1689       }   
1690       if (fSplitMode.Length()) {
1691          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1692          fGridJDL->SetDescription("Split", "We split per SE or file");
1693       }
1694       fMergingJDL->SetValue("Split", "\"se\""); 
1695       fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1696       if (!fAliROOTVersion.IsNull()) {
1697          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1698          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1699       }   
1700       if (!fROOTVersion.IsNull()) {
1701          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1702          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1703       }   
1704       if (!fAPIVersion.IsNull()) {
1705          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1706          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1707       }   
1708       if (!fExternalPackages.IsNull()) {
1709          arr = fExternalPackages.Tokenize(" ");
1710          TIter next(arr);
1711          while ((os=(TObjString*)next())) {
1712             TString pkgname = os->GetString();
1713             Int_t index = pkgname.Index("::");
1714             TString pkgversion = pkgname(index+2, pkgname.Length());
1715             pkgname.Remove(index);
1716             fGridJDL->AddToPackages(pkgname, pkgversion);
1717             fMergingJDL->AddToPackages(pkgname, pkgversion);
1718          }   
1719          delete arr;   
1720       }   
1721       fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1722       fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1723       fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1724       fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1725       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1726       TString analysisFile = fExecutable;
1727       analysisFile.ReplaceAll(".sh", ".root");
1728       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1729       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1730       if (fAdditionalLibs.Length()) {
1731          arr = fAdditionalLibs.Tokenize(" ");
1732          TIter next(arr);
1733          while ((os=(TObjString*)next())) {
1734             if (os->GetString().Contains(".so")) continue;
1735             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1736             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1737          }   
1738          delete arr;   
1739       }
1740       if (fPackages) {
1741          TIter next(fPackages);
1742          TObject *obj;
1743          while ((obj=next())) {
1744             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1745             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1746          }
1747       }
1748       const char *comment = "List of output files and archives";
1749       if (fOutputArchive.Length()) {
1750          TString outputArchive = fOutputArchive;
1751          if (!fRegisterExcludes.IsNull()) {
1752             arr = fRegisterExcludes.Tokenize(" ");
1753             TIter next1(arr);
1754             while ((os=(TObjString*)next1())) {
1755                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1756                outputArchive.ReplaceAll(os->GetString(),"");
1757             } 
1758             delete arr;
1759          }     
1760          arr = outputArchive.Tokenize(" ");
1761          TIter next(arr);
1762          Bool_t first = kTRUE;
1763          while ((os=(TObjString*)next())) {
1764             if (!os->GetString().Contains("@") && fCloseSE.Length())
1765                fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
1766             else
1767                fGridJDL->AddToSet("Output", os->GetString());
1768             if (first) fGridJDL->AddToSetDescription("Output", comment);
1769             first = kFALSE;   
1770          }      
1771          delete arr;
1772          // Output archive for the merging jdl
1773          if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1774             outputArchive = "log_archive.zip:std*@disk=1 ";
1775             // Add normal output files, extra files + terminate files
1776             TString files = GetListOfFiles("outextter");
1777             // Do not register files in fRegisterExcludes
1778             if (!fRegisterExcludes.IsNull()) {
1779                arr = fRegisterExcludes.Tokenize(" ");
1780                TIter next1(arr);
1781                while ((os=(TObjString*)next1())) {
1782                   files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1783                   files.ReplaceAll(os->GetString(),"");
1784                }   
1785                delete arr;
1786             }
1787             files.ReplaceAll(".root", "*.root");
1788             
1789             if (mgr->IsCollectThroughput())
1790                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d %s@disk=%d",files.Data(),fNreplicas, mgr->GetFileInfoLog(),fNreplicas);
1791             else
1792                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",files.Data(),fNreplicas);
1793          } else {
1794             TString files = fOutputArchive;
1795             files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1796             outputArchive = files;
1797          }   
1798          arr = outputArchive.Tokenize(" ");
1799          TIter next2(arr);
1800          first = kTRUE;
1801          while ((os=(TObjString*)next2())) {
1802             TString currentfile = os->GetString();
1803             if (!currentfile.Contains("@") && fCloseSE.Length())
1804                fMergingJDL->AddToSet("Output", Form("%s@%s",currentfile.Data(), fCloseSE.Data()));
1805             else
1806                fMergingJDL->AddToSet("Output", currentfile);
1807             if (first) fMergingJDL->AddToSetDescription("Output", comment);
1808             first = kFALSE;   
1809          }      
1810          delete arr;         
1811       }      
1812       arr = fOutputFiles.Tokenize(",");
1813       TIter next(arr);
1814       Bool_t first = kTRUE;
1815       while ((os=(TObjString*)next())) {
1816          // Ignore ouputs in jdl that are also in outputarchive
1817          TString sout = os->GetString();
1818          sout.ReplaceAll("*", "");
1819          sout.ReplaceAll(".root", "");
1820          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1821          if (fOutputArchive.Contains(sout)) continue;
1822          // Ignore fRegisterExcludes
1823          if (fRegisterExcludes.Contains(sout)) continue;
1824          if (!first) comment = NULL;
1825          if (!os->GetString().Contains("@") && fCloseSE.Length())
1826             fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1827          else
1828             fGridJDL->AddToSet("Output", os->GetString());
1829          if (first) fGridJDL->AddToSetDescription("Output", comment); 
1830          if (fMergeExcludes.Contains(sout)) continue;   
1831          if (!os->GetString().Contains("@") && fCloseSE.Length())
1832             fMergingJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1833          else
1834             fMergingJDL->AddToSet("Output", os->GetString());
1835          if (first) fMergingJDL->AddToSetDescription("Output", comment);
1836          first = kFALSE;
1837       }   
1838       delete arr;
1839       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1840       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1841       TString validationScript = fValidationScript;
1842       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1843       validationScript.ReplaceAll(".sh", "_merge.sh");
1844       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1845       if (fMasterResubmitThreshold) {
1846          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1847          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1848       }   
1849       // Write a jdl with 2 input parameters: collection name and output dir name.
1850       WriteJDL(copy);
1851    }
1852    // Copy jdl to grid workspace   
1853    if (copy) {
1854       // Check if an output directory was defined and valid
1855       if (!fGridOutputDir.Length()) {
1856          Error("CreateJDL", "You must define AliEn output directory");
1857          return kFALSE;
1858       } else {
1859          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1860          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1861             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1862                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1863             } else {
1864                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1865                return kFALSE;
1866             }
1867          }
1868          gGrid->Cd(workdir);
1869       }   
1870       if (TestBit(AliAnalysisGrid::kSubmit)) {
1871          TString mergeJDLName = fExecutable;
1872          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1873          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1874          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1875          if (fProductionMode) {
1876             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1877             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1878          }   
1879          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1880          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1881          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1882          if (!copyLocal2Alien("CreateJDL", fJDLName, locjdl)) 
1883             Fatal("","Terminating");
1884 //         TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1885          if (fMergeViaJDL) {
1886             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1887 //            TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1888             if (!copyLocal2Alien("CreateJDL", mergeJDLName.Data(), locjdl1)) 
1889                Fatal("","Terminating");
1890          }   
1891       }
1892       if (fAdditionalLibs.Length()) {
1893          arr = fAdditionalLibs.Tokenize(" ");
1894          TObjString *os;
1895          TIter next(arr);
1896          while ((os=(TObjString*)next())) {
1897             if (os->GetString().Contains(".so")) continue;
1898             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1899             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1900 //            TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1901             if (!copyLocal2Alien("CreateJDL", os->GetString().Data(), 
1902                 Form("%s/%s", workdir.Data(), os->GetString().Data())))
1903               Fatal("","Terminating");
1904          }   
1905          delete arr;   
1906       }
1907       if (fPackages) {
1908          TIter next(fPackages);
1909          TObject *obj;
1910          while ((obj=next())) {
1911             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1912             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1913 //            TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1914             if (!copyLocal2Alien("CreateJDL",obj->GetName(), 
1915                 Form("%s/%s", workdir.Data(), obj->GetName()))) 
1916               Fatal("","Terminating"); 
1917          }   
1918       }      
1919    } 
1920    return kTRUE;
1921 }
1922
1923 //______________________________________________________________________________
1924 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1925 {
1926 // Writes one or more JDL's corresponding to findex. If findex is negative,
1927 // all run numbers are considered in one go (jdl). For non-negative indices
1928 // they correspond to the indices in the array fInputFiles.
1929    if (!fInputFiles) return kFALSE;
1930    TObject *os;
1931    TString workdir;
1932    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1933    workdir += fGridWorkingDir;
1934    TString stageName = "$2";
1935    if (fProductionMode) stageName = "$4";
1936    if (!fMergeDirName.IsNull()) {
1937      fMergingJDL->AddToInputDataCollection(Form("LF:$1/%s/Stage_%s.xml,nodownload",fMergeDirName.Data(),stageName.Data()), "Collection of files to be merged for current stage");
1938      fMergingJDL->SetOutputDirectory(Form("$1/%s/Stage_%s/#alien_counter_03i#",fMergeDirName.Data(),stageName.Data()), "Output directory");
1939    } else {
1940      fMergingJDL->AddToInputDataCollection(Form("LF:$1/Stage_%s.xml,nodownload",stageName.Data()), "Collection of files to be merged for current stage");
1941      fMergingJDL->SetOutputDirectory(Form("$1/Stage_%s/#alien_counter_03i#",stageName.Data()), "Output directory");
1942    }
1943    if (fProductionMode) {
1944       TIter next(fInputFiles);
1945       while ((os=next())) {
1946          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1947       }
1948       if (!fOutputToRunNo)
1949          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1950       else  
1951          fGridJDL->SetOutputDirectory(fGridOutputDir);
1952    } else {            
1953       if (!fRunNumbers.Length() && !fRunRange[0]) {
1954          // One jdl with no parameters in case input data is specified by name.
1955          TIter next(fInputFiles);
1956          while ((os=next()))
1957             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1958          if (!fOutputSingle.IsNull())
1959             fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1960          else {
1961             fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1962             fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1963          }   
1964       } else {
1965          // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1966          fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1967          if (!fOutputSingle.IsNull()) {
1968             if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1969             else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1970          } else {   
1971             fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1972          }   
1973       }
1974    }
1975       
1976    // Generate the JDL as a string
1977    TString sjdl = fGridJDL->Generate();
1978    TString sjdl1 = fMergingJDL->Generate();
1979    // Final merge jdl
1980    if (!fMergeDirName.IsNull()) {
1981      fMergingJDL->SetOutputDirectory(Form("$1/%s",fMergeDirName.Data()), "Output directory");
1982      fMergingJDL->AddToInputSandbox(Form("LF:$1/%s/Stage_%s.xml",fMergeDirName.Data(),stageName.Data()));
1983    } else {  
1984      fMergingJDL->SetOutputDirectory("$1", "Output directory");
1985      fMergingJDL->AddToInputSandbox(Form("LF:$1/Stage_%s.xml",stageName.Data()));
1986    }  
1987    TString sjdl2 = fMergingJDL->Generate();
1988    Int_t index, index1;
1989    sjdl.ReplaceAll("\",\"", "\",\n   \"");
1990    sjdl.ReplaceAll("(member", "\n   (member");
1991    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1992    sjdl.ReplaceAll("{", "{\n   ");
1993    sjdl.ReplaceAll("};", "\n};");
1994    sjdl.ReplaceAll("{\n   \n", "{\n");
1995    sjdl.ReplaceAll("\n\n", "\n");
1996    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1997    sjdl1.ReplaceAll("\",\"", "\",\n   \"");
1998    sjdl1.ReplaceAll("(member", "\n   (member");
1999    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2000    sjdl1.ReplaceAll("{", "{\n   ");
2001    sjdl1.ReplaceAll("};", "\n};");
2002    sjdl1.ReplaceAll("{\n   \n", "{\n");
2003    sjdl1.ReplaceAll("\n\n", "\n");
2004    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
2005    sjdl2.ReplaceAll("\",\"", "\",\n   \"");
2006    sjdl2.ReplaceAll("(member", "\n   (member");
2007    sjdl2.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2008    sjdl2.ReplaceAll("{", "{\n   ");
2009    sjdl2.ReplaceAll("};", "\n};");
2010    sjdl2.ReplaceAll("{\n   \n", "{\n");
2011    sjdl2.ReplaceAll("\n\n", "\n");
2012    sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
2013    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2014    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
2015    index = sjdl.Index("JDLVariables");
2016    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
2017    sjdl += "Workdirectorysize = {\"5000MB\"};";
2018    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2019    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2020    index = fJobTag.Index(":");
2021    if (index < 0) index = fJobTag.Length();
2022    TString jobTag = fJobTag;
2023    if (fProductionMode) jobTag.Insert(index,"_Stage$4");
2024    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", jobTag.Data()));
2025    if (fProductionMode) {   
2026      sjdl1.Prepend("# Generated merging jdl (production mode) \
2027                     \n# $1 = full alien path to output directory to be merged \
2028                     \n# $2 = train number \
2029                     \n# $3 = production (like LHC10b) \
2030                     \n# $4 = merging stage \
2031                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2032      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2033      sjdl2.Prepend("# Generated merging jdl \
2034                     \n# $1 = full alien path to output directory to be merged \
2035                     \n# $2 = train number \
2036                     \n# $3 = production (like LHC10b) \
2037                     \n# $4 = merging stage \
2038                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2039    } else {
2040      sjdl1.Prepend("# Generated merging jdl \
2041                     \n# $1 = full alien path to output directory to be merged \
2042                     \n# $2 = merging stage \
2043                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2044      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2045      sjdl2.Prepend("# Generated merging jdl \
2046                     \n# $1 = full alien path to output directory to be merged \
2047                     \n# $2 = merging stage \
2048                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2049    }
2050    index = sjdl1.Index("JDLVariables");
2051    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
2052    index = sjdl2.Index("JDLVariables");
2053    if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
2054    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2055    sjdl2 += "Workdirectorysize = {\"5000MB\"};";
2056    index = sjdl2.Index("Split =");
2057    if (index>=0) {
2058       index1 = sjdl2.Index("\n", index);
2059       sjdl2.Remove(index, index1-index+1);
2060    }
2061    index = sjdl2.Index("SplitMaxInputFileNumber");
2062    if (index>=0) {
2063       index1 = sjdl2.Index("\n", index);
2064       sjdl2.Remove(index, index1-index+1);
2065    }
2066    index = sjdl2.Index("InputDataCollection");
2067    if (index>=0) {
2068       index1 = sjdl2.Index(";", index);
2069       sjdl2.Remove(index, index1-index+1);
2070    }
2071    index = sjdl2.Index("InputDataListFormat");
2072    if (index>=0) {
2073       index1 = sjdl2.Index("\n", index);
2074       sjdl2.Remove(index, index1-index+1);
2075    }
2076    index = sjdl2.Index("InputDataList");
2077    if (index>=0) {
2078       index1 = sjdl2.Index("\n", index);
2079       sjdl2.Remove(index, index1-index+1);
2080    }
2081    sjdl2.ReplaceAll("wn.xml", Form("Stage_%s.xml",stageName.Data()));
2082    // Write jdl to file
2083    ofstream out;
2084    out.open(fJDLName.Data(), ios::out);
2085    if (out.bad()) {
2086       Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
2087       return kFALSE;
2088    }
2089    out << sjdl << endl;
2090    out.close();
2091    TString mergeJDLName = fExecutable;
2092    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2093    if (fMergeViaJDL) {
2094       ofstream out1;
2095       out1.open(mergeJDLName.Data(), ios::out);
2096       if (out1.bad()) {
2097          Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
2098          return kFALSE;
2099       }
2100       out1 << sjdl1 << endl;
2101       out1.close();
2102       ofstream out2;
2103       TString finalJDL = mergeJDLName;
2104       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2105       out2.open(finalJDL.Data(), ios::out);
2106       if (out2.bad()) {
2107          Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
2108          return kFALSE;
2109       }
2110       out2 << sjdl2 << endl;
2111       out2.close();
2112    }   
2113
2114    // Copy jdl to grid workspace   
2115    if (!copy) {
2116       Info("WriteJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
2117    } else {
2118       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
2119       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
2120       TString finalJDL = mergeJDLName;
2121       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2122       TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
2123       if (fProductionMode) {
2124          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2125          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
2126          locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
2127       }   
2128       if (FileExists(locjdl)) gGrid->Rm(locjdl);
2129       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
2130       if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
2131       Info("WriteJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
2132 //      TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
2133       if (!copyLocal2Alien("WriteJDL",fJDLName.Data(),locjdl.Data())) 
2134          Fatal("","Terminating");
2135       if (fMergeViaJDL) {
2136          Info("WriteJDL", "\n#####   Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
2137 //         TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
2138 //         TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
2139          if (!copyLocal2Alien("WriteJDL",mergeJDLName.Data(),locjdl1.Data()))
2140             Fatal("","Terminating");
2141          if (!copyLocal2Alien("WriteJDL",finalJDL.Data(),locjdl2.Data()))
2142            Fatal("","Terminating");
2143       }   
2144    } 
2145    return kTRUE;
2146 }
2147
2148 //______________________________________________________________________________
2149 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
2150 {
2151 // Returns true if file exists.
2152    if (!gGrid) return kFALSE;
2153    TString slfn = lfn;
2154    slfn.ReplaceAll("alien://","");
2155    TGridResult *res = gGrid->Ls(slfn);
2156    if (!res) return kFALSE;
2157    TMap *map = dynamic_cast<TMap*>(res->At(0));
2158    if (!map) {
2159       delete res;
2160       return kFALSE;
2161    }   
2162    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
2163    if (!objs || !objs->GetString().Length()) {
2164       delete res;
2165       return kFALSE;
2166    }
2167    delete res;   
2168    return kTRUE;
2169 }
2170
2171 //______________________________________________________________________________
2172 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
2173 {
2174 // Returns true if directory exists. Can be also a path.
2175    if (!gGrid) return kFALSE;
2176    // Check if dirname is a path
2177    TString dirstripped = dirname;
2178    dirstripped = dirstripped.Strip();
2179    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
2180    TString dir = gSystem->BaseName(dirstripped);
2181    dir += "/";
2182    TString path = gSystem->DirName(dirstripped);
2183    TGridResult *res = gGrid->Ls(path, "-F");
2184    if (!res) return kFALSE;
2185    TIter next(res);
2186    TMap *map;
2187    TObject *obj;
2188    while ((map=dynamic_cast<TMap*>(next()))) {
2189       obj = map->GetValue("name");
2190       if (!obj) break;
2191       if (dir == obj->GetName()) {
2192          delete res;
2193          return kTRUE;
2194       }
2195    }
2196    delete res;
2197    return kFALSE;
2198 }      
2199
2200 //______________________________________________________________________________
2201 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
2202 {
2203 // Check input data type.
2204    isCollection = kFALSE;
2205    isXml = kFALSE;
2206    useTags = kFALSE;
2207    if (!gGrid) {
2208       Error("CheckDataType", "No connection to grid");
2209       return;
2210    }
2211    isCollection = IsCollection(lfn);
2212    TString msg = "\n#####   file: ";
2213    msg += lfn;
2214    if (isCollection) {
2215       msg += " type: raw_collection;";
2216    // special treatment for collections
2217       isXml = kFALSE;
2218       // check for tag files in the collection
2219       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
2220       if (!res) {
2221          msg += " using_tags: No (unknown)";
2222          Info("CheckDataType", "%s", msg.Data());
2223          return;
2224       }   
2225       const char* typeStr = res->GetKey(0, "origLFN");
2226       if (!typeStr || !strlen(typeStr)) {
2227          msg += " using_tags: No (unknown)";
2228          Info("CheckDataType", "%s", msg.Data());
2229          return;
2230       }   
2231       TString file = typeStr;
2232       useTags = file.Contains(".tag");
2233       if (useTags) msg += " using_tags: Yes";
2234       else          msg += " using_tags: No";
2235       Info("CheckDataType", "%s", msg.Data());
2236       return;
2237    }
2238    TString slfn(lfn);
2239    slfn.ToLower();
2240    isXml = slfn.Contains(".xml");
2241    if (isXml) {
2242    // Open xml collection and check if there are tag files inside
2243       msg += " type: xml_collection;";
2244       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
2245       if (!coll) {
2246          msg += " using_tags: No (unknown)";
2247          Info("CheckDataType", "%s", msg.Data());
2248          return;
2249       }   
2250       TMap *map = coll->Next();
2251       if (!map) {
2252          msg += " using_tags: No (unknown)";
2253          Info("CheckDataType", "%s", msg.Data());
2254          return;
2255       }   
2256       map = (TMap*)map->GetValue("");
2257       TString file;
2258       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
2259       useTags = file.Contains(".tag");
2260       delete coll;
2261       if (useTags) msg += " using_tags: Yes";
2262       else          msg += " using_tags: No";
2263       Info("CheckDataType", "%s", msg.Data());
2264       return;
2265    }
2266    useTags = slfn.Contains(".tag");
2267    if (slfn.Contains(".root")) msg += " type: root file;";
2268    else                        msg += " type: unknown file;";
2269    if (useTags) msg += " using_tags: Yes";
2270    else          msg += " using_tags: No";
2271    Info("CheckDataType", "%s", msg.Data());
2272 }
2273
2274 //______________________________________________________________________________
2275 void AliAnalysisAlien::EnablePackage(const char *package)
2276 {
2277 // Enables a par file supposed to exist in the current directory.
2278    TString pkg(package);
2279    pkg.ReplaceAll(".par", "");
2280    pkg += ".par";
2281    if (gSystem->AccessPathName(pkg)) {
2282       Fatal("EnablePackage", "Package %s not found", pkg.Data());
2283       return;
2284    }
2285    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
2286       Info("EnablePackage", "AliEn plugin will use .par packages");
2287    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
2288    if (!fPackages) {
2289       fPackages = new TObjArray();
2290       fPackages->SetOwner();
2291    }
2292    fPackages->Add(new TObjString(pkg));
2293 }      
2294
2295 //______________________________________________________________________________
2296 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
2297 {
2298 // Make a tree from files having the location specified in fFileForTestMode. 
2299 // Inspired from JF's CreateESDChain.
2300    if (fFileForTestMode.IsNull()) {
2301       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2302       return NULL;
2303    }
2304    if (gSystem->AccessPathName(fFileForTestMode)) {
2305       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2306       return NULL;
2307    }   
2308    // Open the file
2309    ifstream in;
2310    in.open(fFileForTestMode);
2311    Int_t count = 0;
2312     // Read the input list of files and add them to the chain
2313    TString line;
2314    TString streeName(treeName);
2315    if (IsUseMCchain()) streeName = "TE";
2316    TChain *chain = new TChain(streeName);
2317    TChain *chainFriend = 0;
2318    if (!fFriendChainName.IsNull()) chainFriend = new TChain(streeName);       
2319    while (in.good())
2320    {
2321       in >> line;
2322       if (line.IsNull() || line.BeginsWith("#")) continue;
2323       if (count++ == fNtestFiles) break;
2324       TString esdFile(line);
2325       TFile *file = TFile::Open(esdFile);
2326       if (file && !file->IsZombie()) {
2327          chain->Add(esdFile);
2328          file->Close();
2329          if (!fFriendChainName.IsNull()) {
2330             if (esdFile.Index("#") > -1)
2331                esdFile.Remove(esdFile.Index("#"));
2332             esdFile = gSystem->DirName(esdFile);
2333             esdFile += "/" + fFriendChainName;
2334             file = TFile::Open(esdFile);
2335             if (file && !file->IsZombie()) {
2336                file->Close();
2337                chainFriend->Add(esdFile);
2338             } else {
2339                Fatal("GetChainForTestMode", "Cannot open friend file: %s", esdFile.Data());
2340                return 0;
2341             }   
2342          }
2343       } else {
2344          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
2345       }   
2346    }
2347    in.close();
2348    if (!chain->GetListOfFiles()->GetEntries()) {
2349        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
2350        delete chain;
2351        delete chainFriend;
2352        return NULL;
2353    }
2354 //    chain->ls();
2355    if (!fFriendChainName.IsNull()) chain->AddFriend(chainFriend);
2356    return chain;
2357 }    
2358
2359 //______________________________________________________________________________
2360 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
2361 {
2362 // Get job status for all jobs with jobid>jobidstart.
2363    static char mstatus[20];
2364    mstatus[0] = '\0';
2365    nrunning = 0;
2366    nwaiting = 0;
2367    nerror   = 0;
2368    ndone    = 0;
2369    TGridJobStatusList *list = gGrid->Ps("");
2370    if (!list) return mstatus;
2371    Int_t nentries = list->GetSize();
2372    TGridJobStatus *status;
2373    Int_t pid;
2374    for (Int_t ijob=0; ijob<nentries; ijob++) {
2375       status = (TGridJobStatus *)list->At(ijob);
2376       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)%p)->GetKey(\"queueId\"));", status));
2377       if (pid<jobidstart) continue;
2378       if (pid == lastid) {
2379          gROOT->ProcessLine(Form("sprintf((char*)%p,((TAlienJobStatus*)%p)->GetKey(\"status\"));",mstatus, status));
2380       }   
2381       switch (status->GetStatus()) {
2382          case TGridJobStatus::kWAITING:
2383             nwaiting++; break;
2384          case TGridJobStatus::kRUNNING:
2385             nrunning++; break;
2386          case TGridJobStatus::kABORTED:
2387          case TGridJobStatus::kFAIL:
2388          case TGridJobStatus::kUNKNOWN:
2389             nerror++; break;
2390          case TGridJobStatus::kDONE:
2391             ndone++;
2392       }
2393    }
2394    list->Delete();
2395    delete list;
2396    return mstatus;
2397 }
2398
2399 //______________________________________________________________________________
2400 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
2401 {
2402 // Returns true if file is a collection. Functionality duplicated from
2403 // TAlien::Type() because we don't want to directly depend on TAlien.
2404    if (!gGrid) {
2405       Error("IsCollection", "No connection to grid");
2406       return kFALSE;
2407    }
2408    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
2409    if (!res) return kFALSE;
2410    const char* typeStr = res->GetKey(0, "type");
2411    if (!typeStr || !strlen(typeStr)) return kFALSE;
2412    if (!strcmp(typeStr, "collection")) return kTRUE;
2413    delete res;
2414    return kFALSE;
2415 }   
2416
2417 //______________________________________________________________________________
2418 Bool_t AliAnalysisAlien::IsSingleOutput() const
2419 {
2420 // Check if single-ouput option is on.
2421    return (!fOutputSingle.IsNull());
2422 }
2423    
2424 //______________________________________________________________________________
2425 void AliAnalysisAlien::Print(Option_t *) const
2426 {
2427 // Print current plugin settings.
2428    printf("### AliEn analysis plugin current settings ###\n");
2429    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2430    if (mgr && mgr->IsProofMode()) {
2431       TString proofType = "=   PLUGIN IN PROOF MODE ON CLUSTER:_________________";
2432       if (TestBit(AliAnalysisGrid::kTest))
2433          proofType = "=   PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
2434       printf("%s %s\n", proofType.Data(), fProofCluster.Data());
2435       if (!fProofDataSet.IsNull())
2436       printf("=   Requested data set:___________________________ %s\n", fProofDataSet.Data());
2437       if (fProofReset==1)
2438       printf("=   Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2439       if (fProofReset>1)   
2440       printf("=   Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2441       if (!fROOTVersion.IsNull())
2442       printf("=   ROOT version requested________________________ %s\n", fROOTVersion.Data());
2443       else
2444       printf("=   ROOT version requested________________________ default\n");
2445       printf("=   AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
2446       if (!fAliRootMode.IsNull())
2447       printf("=   Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());  
2448       if (fNproofWorkers)
2449       printf("=   Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
2450       if  (fNproofWorkersPerSlave)
2451       printf("=   Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
2452       if (TestSpecialBit(kClearPackages))
2453       printf("=   ClearPackages requested...\n");
2454       if (fIncludePath.Data())
2455       printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2456       printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2457       if (fPackages && fPackages->GetEntries()) {
2458          TIter next(fPackages);
2459          TObject *obj;
2460          TString list;
2461          while ((obj=next())) list += obj->GetName();
2462          printf("=   Par files to be used: ________________________ %s\n", list.Data());
2463       } 
2464       if (TestSpecialBit(kProofConnectGrid))
2465       printf("=   Requested PROOF connection to grid\n");
2466       return;
2467    }
2468    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
2469    if (fOverwriteMode) {
2470       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
2471             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
2472    }
2473    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
2474    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO:Print");
2475    printf("=   Production mode:______________________________ %d\n", fProductionMode);
2476    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
2477    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
2478    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
2479    if (fUser.Length()) 
2480    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
2481    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
2482    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
2483    TString basedatadir = fGridDataDir;
2484    TString pattern = fDataPattern;
2485    pattern.Strip();
2486    Int_t ind = pattern.Index(" ");
2487    if (ind>=0) {
2488       basedatadir += "/%run%/";
2489       basedatadir += pattern(0, ind);
2490       pattern = pattern(ind+1, pattern.Length());
2491    }   
2492    printf("=   Data base directory path requested: __________ %s\n", basedatadir.Data());
2493    printf("=   Data search pattern: _________________________ %s\n", pattern.Data());
2494    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
2495    if (fRunNumbers.Length()) 
2496    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
2497    if (fRunRange[0])
2498    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
2499    if (!fRunRange[0] && !fRunNumbers.Length()) {
2500       TIter next(fInputFiles);
2501       TObject *obj;
2502       TString list;
2503       while ((obj=next())) list += obj->GetName();
2504       printf("=   Input files to be processed: _________________ %s\n", list.Data());
2505    }
2506    if (TestBit(AliAnalysisGrid::kTest))
2507    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
2508    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
2509    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
2510    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
2511    printf("=   List of outputs that should not be registered: %s\n", fRegisterExcludes.Data());
2512    printf("=   List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
2513    printf("=====================================================================\n");
2514    printf("=   Job price: ___________________________________ %d\n", fPrice);
2515    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
2516    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
2517    if (fMaxInitFailed>0) 
2518    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
2519    if (fMasterResubmitThreshold>0) 
2520    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
2521    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
2522    if (fNrunsPerMaster>0)
2523    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
2524    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
2525    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
2526    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
2527    if (fArguments.Length()) 
2528    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
2529    if (fExecutableArgs.Length()) 
2530    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
2531    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
2532    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
2533    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2534    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
2535    if (fDatasetName)
2536    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
2537    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
2538    if (fIncludePath.Data())
2539    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2540    if (fCloseSE.Length())
2541    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
2542    if (fFriendChainName.Length())
2543    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
2544    if (fPackages && fPackages->GetEntries()) {
2545       TIter next(fPackages);
2546       TObject *obj;
2547       TString list;
2548       while ((obj=next())) list += obj->GetName();
2549       printf("=   Par files to be used: ________________________ %s\n", list.Data());
2550    }   
2551 }
2552
2553 //______________________________________________________________________________
2554 void AliAnalysisAlien::SetDefaults()
2555 {
2556 // Set default values for everything. What cannot be filled will be left empty.
2557    if (fGridJDL) delete fGridJDL;
2558    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2559    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2560    fPrice                      = 1;
2561    fTTL                        = 30000;
2562    fSplitMaxInputFileNumber    = 100;
2563    fMaxInitFailed              = 0;
2564    fMasterResubmitThreshold    = 0;
2565    fNtestFiles                 = 10;
2566    fNreplicas                  = 2;
2567    fRunRange[0]                = 0;
2568    fRunRange[1]                = 0;
2569    fRunPrefix                  = "%d";
2570    fNrunsPerMaster             = 1;
2571    fMaxMergeFiles              = 100;
2572    fRunNumbers                 = "";
2573    fExecutable                 = "analysis.sh";
2574    fExecutableCommand          = "root -b -q -x";
2575    fArguments                  = "";
2576    fExecutableArgs             = "";
2577    fAnalysisMacro              = "myAnalysis.C";
2578    fAnalysisSource             = "";
2579    fAdditionalLibs             = "";
2580    fSplitMode                  = "se";
2581    fAPIVersion                 = "";
2582    fROOTVersion                = "";
2583    fAliROOTVersion             = "";
2584    fUser                       = "";  // Your alien user name
2585    fGridWorkingDir             = "";
2586    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
2587    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
2588    fFriendChainName            = "";
2589    fGridOutputDir              = "output";
2590    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
2591    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
2592    fInputFormat                = "xml-single";
2593    fJDLName                    = "analysis.jdl";
2594    fJobTag                     = "Automatically generated analysis JDL";
2595    fMergeExcludes              = "";
2596    fMergeViaJDL                = 0;
2597    SetUseCopy(kTRUE);
2598    SetCheckCopy(kTRUE);
2599    SetDefaultOutputs(kTRUE);
2600    fOverwriteMode              = 1;
2601 }   
2602
2603 //______________________________________________________________________________
2604 void AliAnalysisAlien::SetFriendChainName(const char *name, const char *libnames)
2605 {
2606    // Set file name for the chain of friends and optionally additional libs to be loaded.
2607    // Libs should be separated by blancs.
2608    fFriendChainName = name;
2609    fFriendLibs = libnames;
2610    if (fFriendLibs.Length()) {
2611      if(!fFriendLibs.Contains(".so"))
2612        Fatal("SetFriendChainName()", "You should provide explicit library names (with extension)");
2613      fFriendLibs.ReplaceAll(",", " ");
2614      fFriendLibs.Strip();
2615      fFriendLibs.ReplaceAll("  ", " ");
2616    }
2617 }
2618
2619 //______________________________________________________________________________
2620 void AliAnalysisAlien::SetRootVersionForProof(const char *version)
2621 {
2622 // Obsolete method. Use SetROOTVersion instead
2623    Warning("SetRootVersionForProof", "Obsolete. Use SetROOTVersion instead");
2624    if (fROOTVersion.IsNull()) SetROOTVersion(version);
2625    else Error("SetRootVersionForProof", "ROOT version already set to %s", fROOTVersion.Data());
2626 }
2627    
2628 //______________________________________________________________________________
2629 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
2630 {
2631 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
2632    // First check if the result is already in the output directory.
2633    if (FileExists(Form("%s/%s",aliendir,filename))) {
2634       printf("Final merged results found. Not merging again.\n");
2635       return kFALSE;
2636    }
2637    // Now check the last stage done.
2638    Int_t stage = 0;
2639    while (1) {
2640       if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
2641       stage++;
2642    }
2643    // Next stage of merging
2644    stage++;
2645    TString pattern = "*root_archive.zip";
2646    if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
2647    TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
2648    if (res) delete res;
2649    // Write standard output to file
2650    gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
2651    // Count the number of files inside
2652    ifstream ifile;
2653    ifile.open(Form("Stage_%d.xml",stage));
2654    if (!ifile.good()) {
2655       ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
2656       return kFALSE;
2657    }   
2658    TString line;
2659    Int_t nfiles = 0;
2660    while (!ifile.eof()) {
2661       ifile >> line;
2662       if (line.Contains("/event")) nfiles++;
2663    }
2664    ifile.close();
2665    if (!nfiles) {
2666       ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
2667       return kFALSE;
2668    } else {
2669       printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
2670    }   
2671    // Copy the file in the output directory
2672    printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
2673 //   TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
2674    if (!copyLocal2Alien("CheckMergedFiles", Form("Stage_%d.xml",stage), 
2675         Form("%s/Stage_%d.xml",aliendir,stage))) Fatal("","Terminating");
2676    // Check if this is the last stage to be done.
2677    Bool_t laststage = (nfiles<nperchunk);
2678    if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
2679    Int_t jobId = 0;
2680    if (laststage) {
2681       printf("### Submiting final merging stage %d\n", stage);
2682       TString finalJDL = jdl;
2683       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2684       TString query = Form("submit %s %s %d", finalJDL.Data(), aliendir, stage);
2685       jobId = SubmitSingleJob(query);
2686    } else {
2687       printf("### Submiting merging stage %d\n", stage);
2688       TString query = Form("submit %s %s %d", jdl, aliendir, stage);
2689       jobId = SubmitSingleJob(query);
2690    }
2691    if (!jobId) return kFALSE;           
2692
2693    if (!fGridJobIDs.IsNull()) fGridJobIDs.Append(" ");
2694    fGridJobIDs.Append(Form("%d", jobId));
2695    if (!fGridStages.IsNull()) fGridStages.Append(" ");
2696    fGridStages.Append(Form("%s_merge_stage%d", 
2697                            laststage ? "final" : "partial", stage));
2698
2699    return kTRUE;   
2700 }        
2701
2702 //______________________________________________________________________________
2703 AliAnalysisManager *AliAnalysisAlien::LoadAnalysisManager(const char *fname)
2704 {
2705 // Loat the analysis manager from a file.
2706    TFile *file = TFile::Open(fname);
2707    if (!file) {
2708       ::Error("LoadAnalysisManager", "Cannot open file %s", fname);
2709       return 0;
2710    }   
2711    TIter nextkey(file->GetListOfKeys());
2712    AliAnalysisManager *mgr = 0;
2713    TKey *key;
2714    while ((key=(TKey*)nextkey())) {
2715       if (!strcmp(key->GetClassName(), "AliAnalysisManager"))
2716          mgr = (AliAnalysisManager*)file->Get(key->GetName());
2717    }
2718    if (!mgr) 
2719       ::Error("LoadAnalysisManager", "No analysis manager found in file %s", fname);
2720    return mgr;
2721 }      
2722
2723 //______________________________________________________________________________
2724 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
2725 {
2726 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
2727    if (!gGrid) return 0;
2728    printf("=> %s ------> ",query);
2729    TGridResult *res = gGrid->Command(query);
2730    if (!res) return 0;
2731    TString jobId = res->GetKey(0,"jobId");
2732    delete res;
2733    if (jobId.IsNull()) {
2734       printf("submission failed. Reason:\n");
2735       gGrid->Stdout();
2736       gGrid->Stderr();
2737       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
2738       return 0;
2739    }
2740    Int_t ijobId = jobId.Atoi();
2741    printf(" Job id: '%s' (%d)\n", jobId.Data(), ijobId);
2742    return ijobId; 
2743 }  
2744
2745 //______________________________________________________________________________
2746 Bool_t AliAnalysisAlien::MergeInfo(const char *output, const char *collection)
2747 {
2748 // Merges a collection of output files using concatenation.
2749    TString scoll(collection);
2750    if (!scoll.Contains(".xml")) return kFALSE;
2751    TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", collection));
2752    if (!coll) {
2753       ::Error("MergeInfo", "Input XML %s collection empty.", collection);
2754       return kFALSE;
2755    }
2756    // Iterate grid collection
2757    TString outtmp;
2758    Bool_t merged = kFALSE;
2759    Int_t ifile = 0;
2760    while (coll->Next()) {
2761       TString fname = gSystem->DirName(coll->GetTURL());
2762       fname += "/";
2763       fname += output;
2764       outtmp = Form("%d_%s", ifile, output);
2765       if (!TFile::Cp(fname, outtmp)) {
2766          ::Error("MergeInfo", "Could not copy %s", fname.Data());
2767          continue;
2768       }
2769       ifile++;
2770       if (ifile<2) {
2771          gSystem->Exec(Form("cp %s lastmerged", outtmp.Data()));
2772          continue;
2773       }
2774       gSystem->Exec(Form("cat lastmerged %s > tempmerged", outtmp.Data()));
2775       gSystem->Exec("cp tempmerged lastmerged");
2776    }
2777    if (ifile) {
2778       gSystem->Exec(Form("cp lastmerged %s", output));
2779       gSystem->Exec(Form("rm tempmerged lastmerged *_%s", output));
2780       merged = kTRUE;
2781    }
2782    return merged;
2783 }   
2784
2785 //______________________________________________________________________________
2786 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
2787 {
2788 // Merge given output files from basedir. Basedir can be an alien output directory
2789 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
2790 // files in a group (ignored for xml input). Merging can be done in stages:
2791 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
2792 // stage=1 : works with an xml of all root_archive.zip in the output directory
2793 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
2794    TString outputFile = output;
2795    TString command;
2796    TString outputChunk;
2797    TString previousChunk = "";
2798    TObjArray *listoffiles = new TObjArray();
2799 //   listoffiles->SetOwner();
2800    Int_t countChunk = 0;
2801    Int_t countZero = nmaxmerge;
2802    Bool_t merged = kTRUE;
2803    Bool_t isGrid = kTRUE;
2804    Int_t index = outputFile.Index("@");
2805    if (index > 0) outputFile.Remove(index);
2806    TString inputFile = outputFile;
2807    TString sbasedir = basedir;
2808    if (sbasedir.Contains(".xml")) {
2809       // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
2810       nmaxmerge = 9999999;
2811       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
2812       if (!coll) {
2813          ::Error("MergeOutput", "Input XML collection empty.");
2814          return kFALSE;
2815       }
2816       // Iterate grid collection
2817       while (coll->Next()) {
2818          TString fname = gSystem->DirName(coll->GetTURL());
2819          fname += "/";
2820          fname += inputFile;      
2821          listoffiles->Add(new TNamed(fname.Data(),""));
2822       }   
2823    } else if (sbasedir.Contains(".txt")) {
2824       // The file having the .txt extension is expected to contain a list of
2825       // folders where the output files will be looked. For alien folders,
2826       // the full folder LFN is expected (starting with alien://)
2827       // Assume lfn's on each line
2828       TString line;
2829       ifstream in;
2830       in.open(sbasedir);
2831       if (in.fail()) {
2832          ::Error("MergeOutput", "File %s cannot be opened. Merging stopped." ,sbasedir.Data());
2833          return kTRUE;
2834       }           
2835       Int_t nfiles = 0;
2836       while (in.good()) {
2837          in >> line;
2838          if (line.IsNull() || line.BeginsWith("#")) continue;
2839          line.Strip();
2840          if (!line.Contains("alien:")) isGrid = kFALSE;
2841          line += "/";
2842          line += outputFile;
2843          nfiles++;
2844          listoffiles->Add(new TNamed(line.Data(),""));
2845       }
2846       in.close();
2847       if (!nfiles) {
2848          ::Error("MergeOutput","Input file %s contains no files to be merged\n", sbasedir.Data());
2849          delete listoffiles;
2850          return kFALSE;
2851       }
2852    } else {   
2853       command = Form("find %s/ *%s", basedir, inputFile.Data());
2854       printf("command: %s\n", command.Data());
2855       TGridResult *res = gGrid->Command(command);
2856       if (!res) {
2857          ::Error("MergeOutput","No result for the find command\n");
2858          delete listoffiles;
2859          return kFALSE;
2860       }     
2861       TIter nextmap(res);
2862       TMap *map = 0;
2863       while ((map=(TMap*)nextmap())) {
2864          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
2865          if (!objs || !objs->GetString().Length()) {
2866             // Nothing found - skip this output
2867             delete res;
2868             delete listoffiles;
2869             return kFALSE;
2870          }
2871          listoffiles->Add(new TNamed(objs->GetName(),""));
2872       }
2873       delete res;
2874    }
2875    if (!listoffiles->GetEntries()) {
2876       ::Error("MergeOutput","No result for the find command\n");
2877       delete listoffiles;
2878       return kFALSE;
2879    }     
2880
2881    TFileMerger *fm = 0;
2882    TIter next0(listoffiles);
2883    TObjArray *listoffilestmp = new TObjArray();
2884    listoffilestmp->SetOwner();
2885    TObject *nextfile;
2886    TString snextfile;
2887    // Keep only the files at upper level
2888    Int_t countChar = 0;
2889    while ((nextfile=next0())) {
2890       snextfile = nextfile->GetName();
2891       Int_t crtCount = snextfile.CountChar('/');
2892       if (nextfile == listoffiles->First()) countChar = crtCount;
2893       if (crtCount < countChar) countChar = crtCount;
2894    }
2895    next0.Reset();
2896    while ((nextfile=next0())) {
2897       snextfile = nextfile->GetName();
2898       Int_t crtCount = snextfile.CountChar('/');
2899       if (crtCount > countChar) {
2900          delete nextfile;
2901          continue;
2902       }   
2903       listoffilestmp->Add(nextfile);
2904    }
2905    delete listoffiles;
2906    listoffiles = listoffilestmp;  // Now contains 'good' files
2907    listoffiles->Print();
2908    TIter next(listoffiles);   
2909    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2910    outputChunk = outputFile;
2911    outputChunk.ReplaceAll(".root", "_*.root");
2912    // Check for existent temporary merge files
2913    // Check overwrite mode and remove previous partial results if needed
2914    // Preserve old merging functionality for stage 0.
2915    if (stage==0) {
2916       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2917          while (1) {
2918             // Skip as many input files as in a chunk
2919             for (Int_t counter=0; counter<nmaxmerge; counter++) {
2920                nextfile = next();
2921                if (!nextfile) {
2922                   ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
2923                   delete listoffiles;
2924                   return kFALSE;
2925                }   
2926                snextfile = nextfile->GetName();
2927             }
2928             outputChunk = outputFile;
2929             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2930             countChunk++;
2931             if (gSystem->AccessPathName(outputChunk)) continue;
2932             // Merged file with chunks up to <countChunk> found
2933             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
2934             previousChunk = outputChunk;
2935             break;
2936          }
2937       }   
2938       countZero = nmaxmerge;
2939    
2940       while ((nextfile=next())) {
2941          snextfile = nextfile->GetName();
2942          // Loop 'find' results and get next LFN
2943          if (countZero == nmaxmerge) {
2944             // First file in chunk - create file merger and add previous chunk if any.
2945             fm = new TFileMerger(isGrid);
2946             fm->SetFastMethod(kTRUE);
2947             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
2948             outputChunk = outputFile;
2949             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2950          }
2951          // If last file found, put merged results in the output file
2952          if (nextfile == listoffiles->Last()) outputChunk = outputFile;
2953          // Add file to be merged and decrement chunk counter.
2954          fm->AddFile(snextfile);
2955          countZero--;
2956          if (countZero==0 || nextfile == listoffiles->Last()) {            
2957             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2958             // Nothing found - skip this output
2959                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2960                merged = kFALSE;
2961                break;
2962             }
2963             fm->OutputFile(outputChunk);
2964             // Merge the outputs, then go to next chunk      
2965             if (!fm->Merge()) {
2966                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2967                merged = kFALSE;
2968                break;
2969             } else {
2970                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
2971                gSystem->Unlink(previousChunk);
2972             }
2973             if (nextfile == listoffiles->Last()) break;
2974             countChunk++;
2975             countZero = nmaxmerge;
2976             previousChunk = outputChunk;
2977          }
2978       }
2979       delete listoffiles;
2980       delete fm;
2981       return merged;
2982    }
2983    // Merging stage different than 0.
2984    // Move to the begining of the requested chunk.
2985    fm = new TFileMerger(isGrid);
2986    fm->SetFastMethod(kTRUE);
2987    while ((nextfile=next())) fm->AddFile(nextfile->GetName());
2988    delete listoffiles;
2989    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2990       // Nothing found - skip this output
2991       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2992       delete fm;
2993       return kFALSE;
2994    }
2995    fm->OutputFile(outputFile);
2996    // Merge the outputs
2997    if (!fm->Merge()) {
2998       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2999       delete fm;
3000       return kFALSE;
3001    } else {
3002       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
3003    }
3004    delete fm;
3005    return kTRUE;
3006
3007
3008 //______________________________________________________________________________
3009 Bool_t AliAnalysisAlien::MergeOutputs()
3010 {
3011 // Merge analysis outputs existing in the AliEn space.
3012    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
3013    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
3014    if (!Connect()) {
3015       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
3016       return kFALSE;
3017    }
3018    if (fMergeViaJDL) {
3019       if (!TestBit(AliAnalysisGrid::kMerge)) {
3020          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
3021          return kFALSE; 
3022       }     
3023       if (fProductionMode) {
3024          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
3025          return kFALSE;
3026       }
3027       Info("MergeOutputs", "Submitting merging JDL");
3028       if (!SubmitMerging()) return kFALSE;
3029       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
3030       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
3031       return kFALSE;
3032    }   
3033    // Get the output path
3034    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3035    if (!DirectoryExists(fGridOutputDir)) {
3036       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
3037       return kFALSE;
3038    }
3039    if (!fOutputFiles.Length()) {
3040       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3041       return kFALSE;
3042    }
3043    // Check if fast read option was requested
3044    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
3045         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
3046    if (fFastReadOption) {
3047       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
3048              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3049       gEnv->SetValue("XNet.ConnectTimeout",50);
3050       gEnv->SetValue("XNet.RequestTimeout",50);
3051       gEnv->SetValue("XNet.MaxRedirectCount",2);
3052       gEnv->SetValue("XNet.ReconnectTimeout",50);
3053       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
3054    }   
3055    // Make sure we change the temporary directory
3056    gSystem->Setenv("TMPDIR", gSystem->pwd());
3057    // Set temporary compilation directory to current one
3058    gSystem->SetBuildDir(gSystem->pwd(), kTRUE);   
3059    TObjArray *list = fOutputFiles.Tokenize(",");
3060    TIter next(list);
3061    TObjString *str;
3062    TString outputFile;
3063    Bool_t merged = kTRUE;
3064    while((str=(TObjString*)next())) {
3065       outputFile = str->GetString();
3066       Int_t index = outputFile.Index("@");
3067       if (index > 0) outputFile.Remove(index);
3068       TString outputChunk = outputFile;
3069       outputChunk.ReplaceAll(".root", "_*.root");
3070       // Skip already merged outputs
3071       if (!gSystem->AccessPathName(outputFile)) {
3072          if (fOverwriteMode) {
3073             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
3074             gSystem->Unlink(outputFile);
3075             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3076                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
3077                      outputChunk.Data());
3078                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
3079             }
3080          } else {   
3081             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
3082             continue;
3083          }   
3084       } else {
3085          if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3086             Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
3087                   outputChunk.Data());
3088             gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
3089          }   
3090       }
3091       if (fMergeExcludes.Contains(outputFile.Data()) || 
3092           fRegisterExcludes.Contains(outputFile.Data())) continue;
3093       // Perform a 'find' command in the output directory, looking for registered outputs    
3094       merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
3095       if (!merged) {
3096          Error("MergeOutputs", "Terminate() will  NOT be executed");
3097          delete list;
3098          return kFALSE;
3099       }
3100       TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
3101       if (fileOpened) fileOpened->Close();
3102    } 
3103    delete list;
3104    return kTRUE;
3105 }   
3106
3107 //______________________________________________________________________________
3108 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
3109 {
3110 // Use the output files connected to output containers from the analysis manager
3111 // rather than the files defined by SetOutputFiles
3112    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
3113       Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
3114    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
3115 }
3116       
3117 //______________________________________________________________________________
3118 void AliAnalysisAlien::SetOutputFiles(const char *list)
3119 {
3120 // Manually set the output files list.
3121 // Removes duplicates. Not allowed if default outputs are not disabled.
3122    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
3123       Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
3124       return;
3125    }
3126    Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
3127    fOutputFiles = "";
3128    TString slist = list;
3129    if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
3130    TObjArray *arr = slist.Tokenize(" "); 
3131    TObjString *os;
3132    TIter next(arr);
3133    TString sout;
3134    while ((os=(TObjString*)next())) {
3135       sout = os->GetString();
3136       if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
3137       if (fOutputFiles.Contains(sout)) continue;
3138       if (!fOutputFiles.IsNull()) fOutputFiles += ",";
3139       fOutputFiles += sout;
3140    }
3141    delete arr;   
3142 }
3143
3144 //______________________________________________________________________________
3145 void AliAnalysisAlien::SetOutputArchive(const char *list)
3146 {
3147 // Manually set the output archive list. Free text - you are on your own...
3148 // Not allowed if default outputs are not disabled.
3149    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
3150       Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
3151       return;
3152    }
3153    Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
3154    fOutputArchive = list;
3155 }
3156
3157 //______________________________________________________________________________
3158 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
3159 {
3160 // Setting a prefered output SE is not allowed anymore.
3161    Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
3162 }
3163
3164 //______________________________________________________________________________
3165 void AliAnalysisAlien::SetProofParameter(const char *pname, const char *value)
3166 {
3167 // Set some PROOF special parameter.
3168    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
3169    if (pair) {
3170       TObject *old = pair->Key();
3171  &n