]> git.uio.no Git - u/mrichter/AliRoot.git/blame - ANALYSIS/AliAnalysisAlien.cxx
High multiplicity settings
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisAlien.cxx
CommitLineData
c57f56b7 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 "Riostream.h"
0f389141 24#include "TEnv.h"
7c2cd90a 25#include "TBits.h"
0f389141 26#include "TError.h"
c57f56b7 27#include "TROOT.h"
28#include "TSystem.h"
29#include "TFile.h"
30#include "TObjString.h"
31#include "TObjArray.h"
32#include "TGrid.h"
33#include "TGridResult.h"
34#include "TGridCollection.h"
35#include "TGridJDL.h"
d2a409b2 36#include "TGridJobStatusList.h"
37#include "TGridJobStatus.h"
c57f56b7 38#include "TFileMerger.h"
39#include "AliAnalysisManager.h"
bb885a9e 40#include "AliVEventHandler.h"
41#include "AliAnalysisDataContainer.h"
c57f56b7 42#include "AliAnalysisAlien.h"
43
44ClassImp(AliAnalysisAlien)
45
46//______________________________________________________________________________
47AliAnalysisAlien::AliAnalysisAlien()
48 :AliAnalysisGrid(),
49 fGridJDL(NULL),
0f389141 50 fMergingJDL(NULL),
c57f56b7 51 fPrice(0),
52 fTTL(0),
53 fSplitMaxInputFileNumber(0),
54 fMaxInitFailed(0),
55 fMasterResubmitThreshold(0),
bb885a9e 56 fNtestFiles(0),
319593fb 57 fNrunsPerMaster(0),
16a4353c 58 fMaxMergeFiles(0),
d2a409b2 59 fNsubmitted(0),
a3e84053 60 fProductionMode(0),
cd11251e 61 fOutputToRunNo(0),
0f389141 62 fMergeViaJDL(0),
63 fFastReadOption(0),
e1c22e21 64 fOverwriteMode(1),
149d288c 65 fNreplicas(2),
c57f56b7 66 fRunNumbers(),
67 fExecutable(),
0a1c1f7f 68 fExecutableCommand(),
c57f56b7 69 fArguments(),
631c0b05 70 fExecutableArgs(),
c57f56b7 71 fAnalysisMacro(),
72 fAnalysisSource(),
d5c6455a 73 fAdditionalRootLibs(),
c57f56b7 74 fAdditionalLibs(),
75 fSplitMode(),
76 fAPIVersion(),
77 fROOTVersion(),
78 fAliROOTVersion(),
648174cf 79 fExternalPackages(),
c57f56b7 80 fUser(),
81 fGridWorkingDir(),
82 fGridDataDir(),
83 fDataPattern(),
84 fGridOutputDir(),
85 fOutputArchive(),
86 fOutputFiles(),
87 fInputFormat(),
e7c71df0 88 fDatasetName(),
c57f56b7 89 fJDLName(),
bb885a9e 90 fMergeExcludes(),
f965131e 91 fIncludePath(),
bb885a9e 92 fCloseSE(),
0df6ccf2 93 fFriendChainName(),
c6cb3634 94 fJobTag(),
648174cf 95 fOutputSingle(),
5fce53f4 96 fRunPrefix(),
4e5c5506 97 fInputFiles(0),
98 fPackages(0)
c57f56b7 99{
100// Dummy ctor.
101 SetDefaults();
102}
103
104//______________________________________________________________________________
105AliAnalysisAlien::AliAnalysisAlien(const char *name)
106 :AliAnalysisGrid(name),
107 fGridJDL(NULL),
0f389141 108 fMergingJDL(NULL),
c57f56b7 109 fPrice(0),
110 fTTL(0),
111 fSplitMaxInputFileNumber(0),
112 fMaxInitFailed(0),
113 fMasterResubmitThreshold(0),
bb885a9e 114 fNtestFiles(0),
319593fb 115 fNrunsPerMaster(0),
16a4353c 116 fMaxMergeFiles(0),
d2a409b2 117 fNsubmitted(0),
a3e84053 118 fProductionMode(0),
cd11251e 119 fOutputToRunNo(0),
0f389141 120 fMergeViaJDL(0),
121 fFastReadOption(0),
e1c22e21 122 fOverwriteMode(1),
149d288c 123 fNreplicas(2),
c57f56b7 124 fRunNumbers(),
125 fExecutable(),
0a1c1f7f 126 fExecutableCommand(),
c57f56b7 127 fArguments(),
631c0b05 128 fExecutableArgs(),
c57f56b7 129 fAnalysisMacro(),
130 fAnalysisSource(),
d5c6455a 131 fAdditionalRootLibs(),
c57f56b7 132 fAdditionalLibs(),
133 fSplitMode(),
134 fAPIVersion(),
135 fROOTVersion(),
136 fAliROOTVersion(),
648174cf 137 fExternalPackages(),
c57f56b7 138 fUser(),
139 fGridWorkingDir(),
140 fGridDataDir(),
141 fDataPattern(),
142 fGridOutputDir(),
143 fOutputArchive(),
144 fOutputFiles(),
145 fInputFormat(),
e7c71df0 146 fDatasetName(),
c57f56b7 147 fJDLName(),
bb885a9e 148 fMergeExcludes(),
f965131e 149 fIncludePath(),
bb885a9e 150 fCloseSE(),
0df6ccf2 151 fFriendChainName(),
c6cb3634 152 fJobTag(),
648174cf 153 fOutputSingle(),
5fce53f4 154 fRunPrefix(),
4e5c5506 155 fInputFiles(0),
156 fPackages(0)
c57f56b7 157{
158// Default ctor.
159 SetDefaults();
160}
161
162//______________________________________________________________________________
163AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
164 :AliAnalysisGrid(other),
165 fGridJDL(NULL),
0f389141 166 fMergingJDL(NULL),
c57f56b7 167 fPrice(other.fPrice),
168 fTTL(other.fTTL),
169 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
170 fMaxInitFailed(other.fMaxInitFailed),
171 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
bb885a9e 172 fNtestFiles(other.fNtestFiles),
319593fb 173 fNrunsPerMaster(other.fNrunsPerMaster),
16a4353c 174 fMaxMergeFiles(other.fMaxMergeFiles),
d2a409b2 175 fNsubmitted(other.fNsubmitted),
a3e84053 176 fProductionMode(other.fProductionMode),
cd11251e 177 fOutputToRunNo(other.fOutputToRunNo),
0f389141 178 fMergeViaJDL(other.fMergeViaJDL),
179 fFastReadOption(other.fFastReadOption),
180 fOverwriteMode(other.fOverwriteMode),
149d288c 181 fNreplicas(other.fNreplicas),
c57f56b7 182 fRunNumbers(other.fRunNumbers),
183 fExecutable(other.fExecutable),
0a1c1f7f 184 fExecutableCommand(other.fExecutableCommand),
c57f56b7 185 fArguments(other.fArguments),
631c0b05 186 fExecutableArgs(other.fExecutableArgs),
c57f56b7 187 fAnalysisMacro(other.fAnalysisMacro),
188 fAnalysisSource(other.fAnalysisSource),
d5c6455a 189 fAdditionalRootLibs(other.fAdditionalRootLibs),
c57f56b7 190 fAdditionalLibs(other.fAdditionalLibs),
191 fSplitMode(other.fSplitMode),
192 fAPIVersion(other.fAPIVersion),
193 fROOTVersion(other.fROOTVersion),
194 fAliROOTVersion(other.fAliROOTVersion),
648174cf 195 fExternalPackages(other.fExternalPackages),
c57f56b7 196 fUser(other.fUser),
197 fGridWorkingDir(other.fGridWorkingDir),
198 fGridDataDir(other.fGridDataDir),
199 fDataPattern(other.fDataPattern),
200 fGridOutputDir(other.fGridOutputDir),
201 fOutputArchive(other.fOutputArchive),
202 fOutputFiles(other.fOutputFiles),
203 fInputFormat(other.fInputFormat),
e7c71df0 204 fDatasetName(other.fDatasetName),
c57f56b7 205 fJDLName(other.fJDLName),
bb885a9e 206 fMergeExcludes(other.fMergeExcludes),
f965131e 207 fIncludePath(other.fIncludePath),
bb885a9e 208 fCloseSE(other.fCloseSE),
0df6ccf2 209 fFriendChainName(other.fFriendChainName),
c6cb3634 210 fJobTag(other.fJobTag),
648174cf 211 fOutputSingle(other.fOutputSingle),
5fce53f4 212 fRunPrefix(other.fRunPrefix),
4e5c5506 213 fInputFiles(0),
214 fPackages(0)
c57f56b7 215{
216// Copy ctor.
217 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
0f389141 218 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
a8739e8a 219 fRunRange[0] = other.fRunRange[0];
220 fRunRange[1] = other.fRunRange[1];
c57f56b7 221 if (other.fInputFiles) {
222 fInputFiles = new TObjArray();
223 TIter next(other.fInputFiles);
224 TObject *obj;
225 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
226 fInputFiles->SetOwner();
227 }
4e5c5506 228 if (other.fPackages) {
229 fPackages = new TObjArray();
230 TIter next(other.fPackages);
231 TObject *obj;
232 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
233 fPackages->SetOwner();
234 }
c57f56b7 235}
236
237//______________________________________________________________________________
238AliAnalysisAlien::~AliAnalysisAlien()
239{
240// Destructor.
241 if (fGridJDL) delete fGridJDL;
0f389141 242 if (fMergingJDL) delete fMergingJDL;
c57f56b7 243 if (fInputFiles) delete fInputFiles;
4e5c5506 244 if (fPackages) delete fPackages;
c57f56b7 245}
246
247//______________________________________________________________________________
248AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
249{
250// Assignment.
251 if (this != &other) {
252 AliAnalysisGrid::operator=(other);
253 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
0f389141 254 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
c57f56b7 255 fPrice = other.fPrice;
256 fTTL = other.fTTL;
257 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
258 fMaxInitFailed = other.fMaxInitFailed;
259 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
bb885a9e 260 fNtestFiles = other.fNtestFiles;
a3e84053 261 fNrunsPerMaster = other.fNrunsPerMaster;
262 fMaxMergeFiles = other.fMaxMergeFiles;
263 fNsubmitted = other.fNsubmitted;
264 fProductionMode = other.fProductionMode;
cd11251e 265 fOutputToRunNo = other.fOutputToRunNo;
0f389141 266 fMergeViaJDL = other.fMergeViaJDL;
267 fFastReadOption = other.fFastReadOption;
268 fOverwriteMode = other.fOverwriteMode;
149d288c 269 fNreplicas = other.fNreplicas;
c57f56b7 270 fRunNumbers = other.fRunNumbers;
271 fExecutable = other.fExecutable;
0a1c1f7f 272 fExecutableCommand = other.fExecutableCommand;
c57f56b7 273 fArguments = other.fArguments;
631c0b05 274 fExecutableArgs = other.fExecutableArgs;
c57f56b7 275 fAnalysisMacro = other.fAnalysisMacro;
276 fAnalysisSource = other.fAnalysisSource;
d5c6455a 277 fAdditionalRootLibs = other.fAdditionalRootLibs;
c57f56b7 278 fAdditionalLibs = other.fAdditionalLibs;
279 fSplitMode = other.fSplitMode;
280 fAPIVersion = other.fAPIVersion;
281 fROOTVersion = other.fROOTVersion;
282 fAliROOTVersion = other.fAliROOTVersion;
648174cf 283 fExternalPackages = other.fExternalPackages;
c57f56b7 284 fUser = other.fUser;
285 fGridWorkingDir = other.fGridWorkingDir;
286 fGridDataDir = other.fGridDataDir;
287 fDataPattern = other.fDataPattern;
288 fGridOutputDir = other.fGridOutputDir;
289 fOutputArchive = other.fOutputArchive;
290 fOutputFiles = other.fOutputFiles;
291 fInputFormat = other.fInputFormat;
e7c71df0 292 fDatasetName = other.fDatasetName;
c57f56b7 293 fJDLName = other.fJDLName;
bb885a9e 294 fMergeExcludes = other.fMergeExcludes;
f965131e 295 fIncludePath = other.fIncludePath;
bb885a9e 296 fCloseSE = other.fCloseSE;
0df6ccf2 297 fFriendChainName = other.fFriendChainName;
c6cb3634 298 fJobTag = other.fJobTag;
648174cf 299 fOutputSingle = other.fOutputSingle;
5fce53f4 300 fRunPrefix = other.fRunPrefix;
c57f56b7 301 if (other.fInputFiles) {
302 fInputFiles = new TObjArray();
303 TIter next(other.fInputFiles);
304 TObject *obj;
305 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
306 fInputFiles->SetOwner();
307 }
4e5c5506 308 if (other.fPackages) {
309 fPackages = new TObjArray();
310 TIter next(other.fPackages);
311 TObject *obj;
312 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
313 fPackages->SetOwner();
314 }
c57f56b7 315 }
316 return *this;
317}
318
f965131e 319//______________________________________________________________________________
320void AliAnalysisAlien::AddIncludePath(const char *path)
321{
322// Add include path in the remote analysis macro.
323 TString p(path);
324 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
325 else fIncludePath += Form("-I%s ", path);
326}
327
c57f56b7 328//______________________________________________________________________________
329void AliAnalysisAlien::AddRunNumber(Int_t run)
330{
331// Add a run number to the list of runs to be processed.
332 if (fRunNumbers.Length()) fRunNumbers += " ";
5fce53f4 333 fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
c57f56b7 334}
335
ee75cfc3 336//______________________________________________________________________________
337void AliAnalysisAlien::AddRunNumber(const char* run)
338{
339// Add a run number to the list of runs to be processed.
340 if (fRunNumbers.Length()) fRunNumbers += " ";
341 fRunNumbers += run;
342}
343
c57f56b7 344//______________________________________________________________________________
345void AliAnalysisAlien::AddDataFile(const char *lfn)
346{
347// Adds a data file to the input to be analysed. The file should be a valid LFN
348// or point to an existing file in the alien workdir.
349 if (!fInputFiles) fInputFiles = new TObjArray();
350 fInputFiles->Add(new TObjString(lfn));
351}
648174cf 352
353//______________________________________________________________________________
354void AliAnalysisAlien::AddExternalPackage(const char *package)
355{
356// Adds external packages w.r.t to the default ones (root,aliroot and gapi)
357 if (fExternalPackages) fExternalPackages += " ";
358 fExternalPackages += package;
359}
360
c57f56b7 361//______________________________________________________________________________
362Bool_t AliAnalysisAlien::Connect()
363{
364// Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
365 if (gGrid && gGrid->IsConnected()) return kTRUE;
c57f56b7 366 if (!gGrid) {
367 Info("Connect", "Trying to connect to AliEn ...");
368 TGrid::Connect("alien://");
369 }
370 if (!gGrid || !gGrid->IsConnected()) {
371 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
372 return kFALSE;
373 }
374 fUser = gGrid->GetUser();
375 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
376 return kTRUE;
377}
378
379//______________________________________________________________________________
380void AliAnalysisAlien::CdWork()
381{
382// Check validity of alien workspace. Create directory if possible.
383 if (!Connect()) {
384 Error("CdWork", "Alien connection required");
385 return;
386 }
387 TString homedir = gGrid->GetHomeDirectory();
388 TString workdir = homedir + fGridWorkingDir;
923e2ca5 389 if (DirectoryExists(workdir)) {
390 gGrid->Cd(workdir);
391 return;
392 }
393 // Work directory not existing - create it
394 gGrid->Cd(homedir);
395 if (gGrid->Mkdir(workdir)) {
396 gGrid->Cd(fGridWorkingDir);
397 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
398 } else {
399 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
400 workdir.Data(), homedir.Data());
401 fGridWorkingDir = "";
402 }
c57f56b7 403}
404
348be253 405//______________________________________________________________________________
406Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
407{
408// Check if file copying is possible.
409 if (!Connect()) {
410 Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
411 return kFALSE;
412 }
d3339be3 413 Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
414 \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
348be253 415 // Check if alien_CLOSE_SE is defined
416 TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
417 if (!closeSE.IsNull()) {
418 Info("CheckFileCopy", "Your current close storage is pointing to: \
419 \n alien_CLOSE_SE = \"%s\"", closeSE.Data());
420 } else {
421 Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
422 }
423 // Check if grid directory exists.
424 if (!DirectoryExists(alienpath)) {
425 Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
426 return kFALSE;
427 }
d3339be3 428 TFile f("plugin_test_copy", "RECREATE");
348be253 429 // User may not have write permissions to current directory
430 if (f.IsZombie()) {
431 Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
432 gSystem->WorkingDirectory());
433 return kFALSE;
434 }
435 f.Close();
d3339be3 436 if (FileExists(Form("alien://%s/%s",alienpath, f.GetName()))) gGrid->Rm(Form("alien://%s/%s",alienpath, f.GetName()));
437 if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, f.GetName()))) {
438 Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
348be253 439 \n# 1. Make sure you have write permissions there. If this is the case: \
440 \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
441 \n# Do: export alien_CLOSE_SE=\"working_disk_SE\" \
442 \n# To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
443 \n# Redo token: rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
444 gSystem->Unlink(f.GetName());
445 return kFALSE;
446 }
447 gSystem->Unlink(f.GetName());
d3339be3 448 gGrid->Rm(Form("%s%s",alienpath,f.GetName()));
449 Info("CheckFileCopy", "### ...SUCCESS ###");
348be253 450 return kTRUE;
451}
452
c57f56b7 453//______________________________________________________________________________
454Bool_t AliAnalysisAlien::CheckInputData()
455{
456// Check validity of input data. If necessary, create xml files.
a8739e8a 457 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
d2a409b2 458 if (!fGridDataDir.Length()) {
459 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
460 return kFALSE;
461 }
462 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
463 return kTRUE;
c57f56b7 464 }
465 // Process declared files
a2f5fc01 466 Bool_t isCollection = kFALSE;
467 Bool_t isXml = kFALSE;
468 Bool_t useTags = kFALSE;
c57f56b7 469 Bool_t checked = kFALSE;
470 CdWork();
471 TString file;
472 TString workdir = gGrid->GetHomeDirectory();
473 workdir += fGridWorkingDir;
474 if (fInputFiles) {
475 TObjString *objstr;
476 TIter next(fInputFiles);
477 while ((objstr=(TObjString*)next())) {
478 file = workdir;
479 file += "/";
480 file += objstr->GetString();
481 // Store full lfn path
482 if (FileExists(file)) objstr->SetString(file);
483 else {
484 file = objstr->GetName();
485 if (!FileExists(objstr->GetName())) {
486 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
487 objstr->GetName(), workdir.Data());
488 return kFALSE;
489 }
490 }
491 Bool_t iscoll, isxml, usetags;
492 CheckDataType(file, iscoll, isxml, usetags);
493 if (!checked) {
494 checked = kTRUE;
a2f5fc01 495 isCollection = iscoll;
496 isXml = isxml;
497 useTags = usetags;
498 TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
c57f56b7 499 } else {
a2f5fc01 500 if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
c57f56b7 501 Error("CheckInputData", "Some conflict was found in the types of inputs");
502 return kFALSE;
503 }
504 }
505 }
506 }
507 // Process requested run numbers
a8739e8a 508 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
c57f56b7 509 // Check validity of alien data directory
510 if (!fGridDataDir.Length()) {
511 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
512 return kFALSE;
513 }
923e2ca5 514 if (!DirectoryExists(fGridDataDir)) {
c57f56b7 515 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
516 return kFALSE;
517 }
a2f5fc01 518 if (isCollection) {
c57f56b7 519 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
520 return kFALSE;
521 }
522
a2f5fc01 523 if (checked && !isXml) {
c57f56b7 524 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
525 return kFALSE;
526 }
527 // Check validity of run number(s)
528 TObjArray *arr;
529 TObjString *os;
319593fb 530 Int_t nruns = 0;
904f9f5f 531 TString schunk, schunk2;
c57f56b7 532 TString path;
533 if (!checked) {
534 checked = kTRUE;
a2f5fc01 535 useTags = fDataPattern.Contains("tag");
536 TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
c57f56b7 537 }
a2f5fc01 538 if (useTags != fDataPattern.Contains("tag")) {
c57f56b7 539 Error("CheckInputData", "Cannot mix input files using/not using tags");
540 return kFALSE;
541 }
542 if (fRunNumbers.Length()) {
a8739e8a 543 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
c57f56b7 544 arr = fRunNumbers.Tokenize(" ");
545 TIter next(arr);
546 while ((os=(TObjString*)next())) {
547 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
923e2ca5 548 if (!DirectoryExists(path)) {
549 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
a8739e8a 550 continue;
c57f56b7 551 }
552 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
553 TString msg = "\n##### file: ";
554 msg += path;
555 msg += " type: xml_collection;";
a2f5fc01 556 if (useTags) msg += " using_tags: Yes";
c57f56b7 557 else msg += " using_tags: No";
558 Info("CheckDataType", msg.Data());
319593fb 559 if (fNrunsPerMaster<2) {
d2a409b2 560 AddDataFile(Form("%s.xml", os->GetString().Data()));
319593fb 561 } else {
562 nruns++;
563 if (((nruns-1)%fNrunsPerMaster) == 0) {
564 schunk = os->GetString();
565 }
566 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
567 schunk += Form("_%s.xml", os->GetString().Data());
d2a409b2 568 AddDataFile(schunk);
319593fb 569 }
c57f56b7 570 }
571 delete arr;
a8739e8a 572 } else {
573 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
574 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
5fce53f4 575 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
923e2ca5 576 if (!DirectoryExists(path)) {
577// Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
a8739e8a 578 continue;
579 }
5fce53f4 580 path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
a8739e8a 581 TString msg = "\n##### file: ";
582 msg += path;
583 msg += " type: xml_collection;";
a2f5fc01 584 if (useTags) msg += " using_tags: Yes";
a8739e8a 585 else msg += " using_tags: No";
586 Info("CheckDataType", msg.Data());
319593fb 587 if (fNrunsPerMaster<2) {
5fce53f4 588 AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
319593fb 589 } else {
590 nruns++;
591 if (((nruns-1)%fNrunsPerMaster) == 0) {
5fce53f4 592 schunk = Form("%s%d", fRunPrefix.Data(),irun);
319593fb 593 }
904f9f5f 594 schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
319593fb 595 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
904f9f5f 596 schunk += schunk2;
d2a409b2 597 AddDataFile(schunk);
319593fb 598 }
a8739e8a 599 }
904f9f5f 600 if (!fInputFiles) {
601 schunk += schunk2;
602 AddDataFile(schunk);
603 }
c57f56b7 604 }
605 return kTRUE;
606}
607
608//______________________________________________________________________________
609Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
610{
611// Create dataset for the grid data directory + run number.
f9e1936d 612 if (TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
c57f56b7 613 if (!Connect()) {
614 Error("CreateDataset", "Cannot create dataset with no grid connection");
615 return kFALSE;
616 }
617
618 // Cd workspace
619 CdWork();
620 TString workdir = gGrid->GetHomeDirectory();
621 workdir += fGridWorkingDir;
622
623 // Compose the 'find' command arguments
624 TString command;
625 TString options = "-x collection ";
bb885a9e 626 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
c57f56b7 627 TString conditions = "";
628
629 TString file;
630 TString path;
319593fb 631 Int_t nruns = 0;
904f9f5f 632 TString schunk, schunk2;
ab254fd1 633 TGridCollection *cbase=0, *cadd=0;
d2a409b2 634 if (!fRunNumbers.Length() && !fRunRange[0]) {
635 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
636 // Make a single data collection from data directory.
637 path = fGridDataDir;
923e2ca5 638 if (!DirectoryExists(path)) {
d2a409b2 639 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
640 return kFALSE;
641 }
923e2ca5 642// CdWork();
d2a409b2 643 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
644 else file = Form("%s.xml", gSystem->BaseName(path));
0f389141 645 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
d2a409b2 646 command = "find ";
647 command += options;
648 command += path;
649 command += " ";
650 command += pattern;
651 command += conditions;
84fcd93f 652 printf("command: %s\n", command.Data());
d2a409b2 653 TGridResult *res = gGrid->Command(command);
654 if (res) delete res;
655 // Write standard output to file
656 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
a2f5fc01 657 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
658 Bool_t nullFile = kFALSE;
659 if (!hasGrep) {
d3339be3 660 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
661 } else {
a2f5fc01 662 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
663 if (nullFile) {
defd7a3a 664 Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
665 return kFALSE;
666 }
d3339be3 667 }
0f389141 668 }
669 Bool_t fileExists = FileExists(file);
670 if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
d2a409b2 671 // Copy xml file to alien space
0f389141 672 if (fileExists) gGrid->Rm(file);
d2a409b2 673 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
674 if (!FileExists(file)) {
675 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
676 return kFALSE;
677 }
678 // Update list of files to be processed.
679 }
680 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
681 return kTRUE;
682 }
c57f56b7 683 // Several runs
a2f5fc01 684 Bool_t nullResult = kTRUE;
a8739e8a 685 if (fRunNumbers.Length()) {
686 TObjArray *arr = fRunNumbers.Tokenize(" ");
687 TObjString *os;
688 TIter next(arr);
689 while ((os=(TObjString*)next())) {
690 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
923e2ca5 691 if (!DirectoryExists(path)) continue;
692// CdWork();
a8739e8a 693 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
694 else file = Form("%s.xml", os->GetString().Data());
319593fb 695 // If local collection file does not exist, create it via 'find' command.
d3339be3 696 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
319593fb 697 command = "find ";
698 command += options;
699 command += path;
700 command += pattern;
701 command += conditions;
702 TGridResult *res = gGrid->Command(command);
703 if (res) delete res;
704 // Write standard output to file
705 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
a2f5fc01 706 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
707 Bool_t nullFile = kFALSE;
708 if (!hasGrep) {
d3339be3 709 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
710 } else {
a2f5fc01 711 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
712 if (nullFile) {
defd7a3a 713 Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
714 fRunNumbers.ReplaceAll(os->GetString().Data(), "");
715 continue;
716 }
d3339be3 717 }
a2f5fc01 718 nullResult = kFALSE;
d3339be3 719 }
a8739e8a 720 if (TestBit(AliAnalysisGrid::kTest)) break;
319593fb 721 // Check if there is one run per master job.
722 if (fNrunsPerMaster<2) {
723 if (FileExists(file)) {
0f389141 724 if (fOverwriteMode) gGrid->Rm(file);
725 else {
726 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
727 continue;
728 }
319593fb 729 }
730 // Copy xml file to alien space
731 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
732 if (!FileExists(file)) {
733 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
734 delete arr;
735 return kFALSE;
736 }
737 } else {
738 nruns++;
739 if (((nruns-1)%fNrunsPerMaster) == 0) {
740 schunk = os->GetString();
741 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
742 } else {
743 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
84fcd93f 744 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
319593fb 745 cbase->Add(cadd);
746 delete cadd;
747 }
748 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
749 continue;
750 }
751 schunk += Form("_%s.xml", os->GetString().Data());
0f389141 752 if (FileExists(schunk)) {
753 if (fOverwriteMode) gGrid->Rm(file);
754 else {
755 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
756 continue;
757 }
319593fb 758 }
84fcd93f 759 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
319593fb 760 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
e95434bc 761 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
319593fb 762 if (!FileExists(schunk)) {
763 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
764 delete arr;
765 return kFALSE;
766 }
d3339be3 767 }
a8739e8a 768 }
769 delete arr;
a2f5fc01 770 if (nullResult) {
d3339be3 771 Error("CreateDataset", "No valid dataset corresponding to the query!");
772 return kFALSE;
773 }
a8739e8a 774 } else {
775 // Process a full run range.
776 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
5fce53f4 777 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
923e2ca5 778 if (!DirectoryExists(path)) continue;
779// CdWork();
a8739e8a 780 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
5fce53f4 781 else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
0f389141 782 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
783 if (fOverwriteMode) gGrid->Rm(file);
784 else {
785 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
786 continue;
787 }
a8739e8a 788 }
319593fb 789 // If local collection file does not exist, create it via 'find' command.
d3339be3 790 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
319593fb 791 command = "find ";
792 command += options;
793 command += path;
794 command += pattern;
795 command += conditions;
796 TGridResult *res = gGrid->Command(command);
797 if (res) delete res;
798 // Write standard output to file
799 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
a2f5fc01 800 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
801 Bool_t nullFile = kFALSE;
802 if (!hasGrep) {
d3339be3 803 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
804 } else {
a2f5fc01 805 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
806 if (nullFile) {
defd7a3a 807 Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
808 continue;
809 }
d3339be3 810 }
a2f5fc01 811 nullResult = kFALSE;
319593fb 812 }
a8739e8a 813 if (TestBit(AliAnalysisGrid::kTest)) break;
319593fb 814 // Check if there is one run per master job.
815 if (fNrunsPerMaster<2) {
816 if (FileExists(file)) {
0f389141 817 if (fOverwriteMode) gGrid->Rm(file);
818 else {
819 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
820 continue;
821 }
319593fb 822 }
823 // Copy xml file to alien space
824 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
825 if (!FileExists(file)) {
826 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
827 return kFALSE;
828 }
829 } else {
830 nruns++;
95e5b448 831 // Check if the collection for the chunk exist locally.
832 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
0f389141 833 if (FileExists(fInputFiles->At(nchunk)->GetName())) {
834 if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
835 else continue;
836 }
84fcd93f 837 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
319593fb 838 if (((nruns-1)%fNrunsPerMaster) == 0) {
904f9f5f 839 schunk = Form("%s%d", fRunPrefix.Data(), irun);
319593fb 840 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
841 } else {
842 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
843 cbase->Add(cadd);
844 delete cadd;
845 }
904f9f5f 846 schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
847 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
319593fb 848 continue;
849 }
904f9f5f 850 schunk = schunk2;
319593fb 851 if (FileExists(schunk)) {
0f389141 852 if (fOverwriteMode) gGrid->Rm(schunk);
853 else {
854 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
855 continue;
856 }
319593fb 857 }
84fcd93f 858 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
319593fb 859 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
95e5b448 860 if (FileExists(schunk)) {
0f389141 861 if (fOverwriteMode) gGrid->Rm(schunk);
862 else {
863 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
864 continue;
865 }
95e5b448 866 }
319593fb 867 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
868 if (!FileExists(schunk)) {
869 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
870 return kFALSE;
871 }
872 }
c57f56b7 873 }
a2f5fc01 874 if (nullResult) {
d3339be3 875 Error("CreateDataset", "No valid dataset corresponding to the query!");
876 return kFALSE;
877 }
a8739e8a 878 }
c57f56b7 879 return kTRUE;
880}
881
882//______________________________________________________________________________
883Bool_t AliAnalysisAlien::CreateJDL()
884{
885// Generate a JDL file according to current settings. The name of the file is
886// specified by fJDLName.
887 Bool_t error = kFALSE;
888 TObjArray *arr = 0;
889 Bool_t copy = kTRUE;
890 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
891 Bool_t generate = kTRUE;
892 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
893 if (!Connect()) {
894 Error("CreateJDL", "Alien connection required");
895 return kFALSE;
896 }
897 // Check validity of alien workspace
898 CdWork();
899 TString workdir = gGrid->GetHomeDirectory();
900 workdir += fGridWorkingDir;
901 if (generate) {
902 TObjString *os;
903 if (!fInputFiles) {
904 Error("CreateJDL()", "Define some input files for your analysis.");
905 error = kTRUE;
906 }
907 // Compose list of input files
908 // Check if output files were defined
909 if (!fOutputFiles.Length()) {
910 Error("CreateJDL", "You must define at least one output file");
911 error = kTRUE;
912 }
913 // Check if an output directory was defined and valid
914 if (!fGridOutputDir.Length()) {
915 Error("CreateJDL", "You must define AliEn output directory");
916 error = kTRUE;
917 } else {
d2a409b2 918 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
923e2ca5 919 if (!DirectoryExists(fGridOutputDir)) {
c57f56b7 920 if (gGrid->Mkdir(fGridOutputDir)) {
921 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
922 } else {
923 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
5513444a 924 // error = kTRUE;
c57f56b7 925 }
926 }
927 gGrid->Cd(workdir);
928 }
929 // Exit if any error up to now
930 if (error) return kFALSE;
931 // Set JDL fields
0f389141 932 if (!fUser.IsNull()) {
933 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
934 fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
935 }
936 fGridJDL->SetExecutable(fExecutable, "This is the startup script");
937 TString mergeExec = fExecutable;
938 mergeExec.ReplaceAll(".sh", "_merge.sh");
939 fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
940 mergeExec.ReplaceAll(".sh", ".C");
941 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
b5b9dee8 942 if (!fArguments.IsNull())
943 fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
7c2cd90a 944 fMergingJDL->SetArguments("$1 $2 $3");
1f0d1ca2 945 fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
946 fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
947 fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
948 fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
949
0f389141 950 if (fMaxInitFailed > 0) {
c57f56b7 951 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
0f389141 952 fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
953 }
954 if (fSplitMaxInputFileNumber > 0) {
c57f56b7 955 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
0f389141 956 fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
957 }
958 if (fSplitMode.Length()) {
c57f56b7 959 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
0f389141 960 fGridJDL->SetDescription("Split", "We split per SE or file");
961 }
962 if (!fAliROOTVersion.IsNull()) {
963 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
964 fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
965 }
966 if (!fROOTVersion.IsNull()) {
c57f56b7 967 fGridJDL->AddToPackages("ROOT", fROOTVersion);
0f389141 968 fMergingJDL->AddToPackages("ROOT", fROOTVersion);
969 }
970 if (!fAPIVersion.IsNull()) {
c57f56b7 971 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
0f389141 972 fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
973 }
648174cf 974 if (!fExternalPackages.IsNull()) {
975 arr = fExternalPackages.Tokenize(" ");
976 TIter next(arr);
977 while ((os=(TObjString*)next())) {
978 TString pkgname = os->GetString();
979 Int_t index = pkgname.Index("::");
980 TString pkgversion = pkgname(index+2, pkgname.Length());
981 pkgname.Remove(index);
982 fGridJDL->AddToPackages(pkgname, pkgversion);
0f389141 983 fMergingJDL->AddToPackages(pkgname, pkgversion);
648174cf 984 }
985 delete arr;
986 }
0f389141 987 fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
988 fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
989 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
f10e8481 990 TString analysisFile = fExecutable;
991 analysisFile.ReplaceAll(".sh", ".root");
992 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
f866cba5 993 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
c57f56b7 994 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
995 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
996 if (fAdditionalLibs.Length()) {
997 arr = fAdditionalLibs.Tokenize(" ");
998 TIter next(arr);
999 while ((os=(TObjString*)next())) {
1000 if (os->GetString().Contains(".so")) continue;
1001 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
0f389141 1002 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
c57f56b7 1003 }
1004 delete arr;
1005 }
4e5c5506 1006 if (fPackages) {
1007 TIter next(fPackages);
1008 TObject *obj;
0f389141 1009 while ((obj=next())) {
4e5c5506 1010 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
0f389141 1011 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1012 }
4e5c5506 1013 }
c57f56b7 1014 if (fOutputArchive.Length()) {
1015 arr = fOutputArchive.Tokenize(" ");
1016 TIter next(arr);
0f389141 1017 Bool_t first = kTRUE;
1018 const char *comment = "Files to be archived";
1019 const char *comment1 = comment;
1020 while ((os=(TObjString*)next())) {
1021 if (!first) comment = NULL;
1022 if (!os->GetString().Contains("@") && fCloseSE.Length())
1023 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1024 else
1025 fGridJDL->AddToOutputArchive(os->GetString(), comment);
1026 first = kFALSE;
1027 }
c57f56b7 1028 delete arr;
0f389141 1029 TString outputArchive = fOutputArchive;
1030 if (!fMergeExcludes.IsNull()) {
1031 arr = fMergeExcludes.Tokenize(" ");
705adb3e 1032 TIter next1(arr);
1033 while ((os=(TObjString*)next1())) {
0f389141 1034 outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1035 outputArchive.ReplaceAll(os->GetString(),"");
1036 }
1037 delete arr;
1038 }
1039 arr = outputArchive.Tokenize(" ");
705adb3e 1040 TIter next2(arr);
0f389141 1041 comment = comment1;
1042 first = kTRUE;
705adb3e 1043 while ((os=(TObjString*)next2())) {
0f389141 1044 if (!first) comment = NULL;
1045 if (!os->GetString().Contains("@") && fCloseSE.Length())
1046 fMergingJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1047 else
1048 fMergingJDL->AddToOutputArchive(os->GetString(), comment);
1049 first = kFALSE;
1050 }
1051 delete arr;
c57f56b7 1052 }
149d288c 1053 arr = fOutputFiles.Tokenize(",");
c57f56b7 1054 TIter next(arr);
0f389141 1055 Bool_t first = kTRUE;
1056 const char *comment = "Files to be archived";
1057 const char *comment1 = comment;
43da816a 1058 while ((os=(TObjString*)next())) {
e1eaf596 1059 // Ignore ouputs in jdl that are also in outputarchive
1060 TString sout = os->GetString();
1061 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1062 if (fOutputArchive.Contains(sout)) continue;
0f389141 1063 if (!first) comment = NULL;
43da816a 1064 if (!os->GetString().Contains("@") && fCloseSE.Length())
0f389141 1065 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
43da816a 1066 else
0f389141 1067 fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1068 first = kFALSE;
43da816a 1069 }
c57f56b7 1070 delete arr;
0f389141 1071 if (fOutputFiles.Length()) {
1072 TString outputFiles = fOutputFiles;
1073 if (!fMergeExcludes.IsNull()) {
1074 arr = fMergeExcludes.Tokenize(" ");
705adb3e 1075 TIter next1(arr);
1076 while ((os=(TObjString*)next1())) {
0f389141 1077 outputFiles.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1078 outputFiles.ReplaceAll(os->GetString(),"");
1079 }
1080 delete arr;
1081 }
1082 arr = outputFiles.Tokenize(" ");
705adb3e 1083 TIter next2(arr);
0f389141 1084 comment = comment1;
1085 first = kTRUE;
705adb3e 1086 while ((os=(TObjString*)next2())) {
0f389141 1087 // Ignore ouputs in jdl that are also in outputarchive
1088 TString sout = os->GetString();
1089 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1090 if (fOutputArchive.Contains(sout)) continue;
1091 if (!first) comment = NULL;
1092 if (!os->GetString().Contains("@") && fCloseSE.Length())
1093 fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1094 else
1095 fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1096 }
1097 delete arr;
1098 }
1099 fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1100 fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
0d5d317c 1101 TString validationScript = fExecutable;
1102 validationScript.ReplaceAll(".sh", "_validation.sh");
0f389141 1103 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1104 validationScript = fExecutable;
1105 validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
1106 fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1107 if (fMasterResubmitThreshold) {
1108 fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1109 fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1110 }
d2a409b2 1111 // Write a jdl with 2 input parameters: collection name and output dir name.
1112 WriteJDL(copy);
c57f56b7 1113 }
1114 // Copy jdl to grid workspace
a8739e8a 1115 if (copy) {
b5e4aaa7 1116 // Check if an output directory was defined and valid
1117 if (!fGridOutputDir.Length()) {
1118 Error("CreateJDL", "You must define AliEn output directory");
1119 return kFALSE;
1120 } else {
1121 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
bb2e67a0 1122 if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
b5e4aaa7 1123 if (gGrid->Mkdir(fGridOutputDir)) {
1124 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
1125 } else {
1126 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1127 return kFALSE;
1128 }
1129 }
1130 gGrid->Cd(workdir);
1131 }
648174cf 1132 if (TestBit(AliAnalysisGrid::kSubmit)) {
0f389141 1133 TString mergeJDLName = fExecutable;
1134 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
648174cf 1135 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
0f389141 1136 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1137 if (fProductionMode) {
648174cf 1138 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
0f389141 1139 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1140 }
648174cf 1141 if (FileExists(locjdl)) gGrid->Rm(locjdl);
0f389141 1142 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1143 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
648174cf 1144 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
0f389141 1145 if (fMergeViaJDL) {
1146 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1147 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1148 }
648174cf 1149 }
c57f56b7 1150 if (fAdditionalLibs.Length()) {
e7c71df0 1151 arr = fAdditionalLibs.Tokenize(" ");
c57f56b7 1152 TObjString *os;
1153 TIter next(arr);
1154 while ((os=(TObjString*)next())) {
c57f56b7 1155 if (os->GetString().Contains(".so")) continue;
4e5c5506 1156 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
c57f56b7 1157 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1158 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1159 }
1160 delete arr;
1161 }
4e5c5506 1162 if (fPackages) {
1163 TIter next(fPackages);
1164 TObject *obj;
1165 while ((obj=next())) {
fdbbc7be 1166 if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
4e5c5506 1167 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
1168 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1169 }
1170 }
c57f56b7 1171 }
1172 return kTRUE;
1173}
1174
a8739e8a 1175//______________________________________________________________________________
d2a409b2 1176Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
a8739e8a 1177{
1178// Writes one or more JDL's corresponding to findex. If findex is negative,
1179// all run numbers are considered in one go (jdl). For non-negative indices
1180// they correspond to the indices in the array fInputFiles.
1181 if (!fInputFiles) return kFALSE;
1182 TObjString *os;
a8739e8a 1183 TString workdir = gGrid->GetHomeDirectory();
1184 workdir += fGridWorkingDir;
d2a409b2 1185
1186 if (!fRunNumbers.Length() && !fRunRange[0]) {
1187 // One jdl with no parameters in case input data is specified by name.
a8739e8a 1188 TIter next(fInputFiles);
1189 while ((os=(TObjString*)next()))
0f389141 1190 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()), "Input xml collections");
648174cf 1191 if (!fOutputSingle.IsNull())
0f389141 1192 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1193 else {
1194 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1195 fMergingJDL->SetOutputDirectory(fGridOutputDir);
1196 }
a8739e8a 1197 } else {
d2a409b2 1198 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
0f389141 1199 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
cd11251e 1200 if (!fOutputSingle.IsNull()) {
0f389141 1201 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1202 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
cd11251e 1203 } else {
0f389141 1204 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1205 fMergingJDL->SetOutputDirectory(Form("%s/$1", fGridOutputDir.Data()), "Output directory");
cd11251e 1206 }
a8739e8a 1207 }
1208
1209
1210 // Generate the JDL as a string
1211 TString sjdl = fGridJDL->Generate();
0f389141 1212 TString sjdl1 = fMergingJDL->Generate();
a8739e8a 1213 Int_t index;
a8739e8a 1214 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1215 sjdl.ReplaceAll("(member", "\n (member");
1216 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1217 sjdl.ReplaceAll("{", "{\n ");
1218 sjdl.ReplaceAll("};", "\n};");
1219 sjdl.ReplaceAll("{\n \n", "{\n");
1220 sjdl.ReplaceAll("\n\n", "\n");
1221 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
0f389141 1222 sjdl1.ReplaceAll("\"LF:", "\n \"LF:");
1223 sjdl1.ReplaceAll("(member", "\n (member");
1224 sjdl1.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1225 sjdl1.ReplaceAll("{", "{\n ");
1226 sjdl1.ReplaceAll("};", "\n};");
1227 sjdl1.ReplaceAll("{\n \n", "{\n");
1228 sjdl1.ReplaceAll("\n\n", "\n");
1229 sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
a8739e8a 1230 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
f60ef0ba 1231 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
a8739e8a 1232 index = sjdl.Index("JDLVariables");
1233 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
0f389141 1234 sjdl1 += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
7c2cd90a 1235 sjdl1.Prepend(Form("Jobtag = {\n \"comment:%s_Merging\"\n};\n", fJobTag.Data()));
1236 sjdl1.Prepend("# Generated merging jdl\n# $1 = full alien path to output directory to be merged\n# $2 = merging stage\n# $3 = merged chunk\n");
0f389141 1237 index = sjdl1.Index("JDLVariables");
1238 if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
a8739e8a 1239 // Write jdl to file
a8739e8a 1240 ofstream out;
d2a409b2 1241 out.open(fJDLName.Data(), ios::out);
a8739e8a 1242 if (out.bad()) {
d2a409b2 1243 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
a8739e8a 1244 return kFALSE;
1245 }
1246 out << sjdl << endl;
0f389141 1247 TString mergeJDLName = fExecutable;
1248 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1249 if (fMergeViaJDL) {
1250 ofstream out1;
1251 out1.open(mergeJDLName.Data(), ios::out);
1252 if (out.bad()) {
1253 Error("CreateJDL", "Bad file name: %s", mergeJDLName.Data());
1254 return kFALSE;
1255 }
1256 out1 << sjdl1 << endl;
1257 }
a8739e8a 1258
1259 // Copy jdl to grid workspace
1260 if (!copy) {
1261 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1262 } else {
d2a409b2 1263 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
0f389141 1264 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1265 if (fProductionMode) {
b5fe9cba 1266 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
0f389141 1267 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1268 }
d2a409b2 1269 if (FileExists(locjdl)) gGrid->Rm(locjdl);
0f389141 1270 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1271 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
5513444a 1272 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
0f389141 1273 if (fMergeViaJDL) {
1274 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1275 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1276 }
a8739e8a 1277 }
1278 return kTRUE;
1279}
1280
c57f56b7 1281//______________________________________________________________________________
5513444a 1282Bool_t AliAnalysisAlien::FileExists(const char *lfn)
c57f56b7 1283{
1284// Returns true if file exists.
5513444a 1285 if (!gGrid) return kFALSE;
c57f56b7 1286 TGridResult *res = gGrid->Ls(lfn);
1287 if (!res) return kFALSE;
1288 TMap *map = dynamic_cast<TMap*>(res->At(0));
1289 if (!map) {
1290 delete res;
1291 return kFALSE;
1292 }
1293 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1294 if (!objs || !objs->GetString().Length()) {
1295 delete res;
1296 return kFALSE;
1297 }
1298 delete res;
1299 return kTRUE;
1300}
1301
923e2ca5 1302//______________________________________________________________________________
1303Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1304{
1305// Returns true if directory exists. Can be also a path.
1306 if (!gGrid) return kFALSE;
1307 // Check if dirname is a path
1308 TString dirstripped = dirname;
1309 dirstripped = dirstripped.Strip();
1310 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1311 TString dir = gSystem->BaseName(dirstripped);
1312 dir += "/";
1313 TString path = gSystem->DirName(dirstripped);
1314 TGridResult *res = gGrid->Ls(path, "-F");
1315 if (!res) return kFALSE;
1316 TIter next(res);
1317 TMap *map;
1318 TObject *obj;
1319 while ((map=dynamic_cast<TMap*>(next()))) {
1320 obj = map->GetValue("name");
1321 if (!obj) break;
1322 if (dir == obj->GetName()) {
1323 delete res;
1324 return kTRUE;
1325 }
1326 }
1327 delete res;
1328 return kFALSE;
1329}
1330
c57f56b7 1331//______________________________________________________________________________
a2f5fc01 1332void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
c57f56b7 1333{
1334// Check input data type.
a2f5fc01 1335 isCollection = kFALSE;
1336 isXml = kFALSE;
1337 useTags = kFALSE;
c57f56b7 1338 if (!gGrid) {
1339 Error("CheckDataType", "No connection to grid");
1340 return;
1341 }
a2f5fc01 1342 isCollection = IsCollection(lfn);
c57f56b7 1343 TString msg = "\n##### file: ";
1344 msg += lfn;
a2f5fc01 1345 if (isCollection) {
c57f56b7 1346 msg += " type: raw_collection;";
1347 // special treatment for collections
a2f5fc01 1348 isXml = kFALSE;
c57f56b7 1349 // check for tag files in the collection
1350 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1351 if (!res) {
1352 msg += " using_tags: No (unknown)";
1353 Info("CheckDataType", msg.Data());
1354 return;
1355 }
1356 const char* typeStr = res->GetKey(0, "origLFN");
1357 if (!typeStr || !strlen(typeStr)) {
1358 msg += " using_tags: No (unknown)";
1359 Info("CheckDataType", msg.Data());
1360 return;
1361 }
1362 TString file = typeStr;
a2f5fc01 1363 useTags = file.Contains(".tag");
1364 if (useTags) msg += " using_tags: Yes";
c57f56b7 1365 else msg += " using_tags: No";
1366 Info("CheckDataType", msg.Data());
1367 return;
1368 }
1369 TString slfn(lfn);
1370 slfn.ToLower();
a2f5fc01 1371 isXml = slfn.Contains(".xml");
1372 if (isXml) {
c57f56b7 1373 // Open xml collection and check if there are tag files inside
1374 msg += " type: xml_collection;";
1375 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1376 if (!coll) {
1377 msg += " using_tags: No (unknown)";
1378 Info("CheckDataType", msg.Data());
1379 return;
1380 }
1381 TMap *map = coll->Next();
1382 if (!map) {
1383 msg += " using_tags: No (unknown)";
1384 Info("CheckDataType", msg.Data());
1385 return;
1386 }
1387 map = (TMap*)map->GetValue("");
1388 TString file;
1389 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
a2f5fc01 1390 useTags = file.Contains(".tag");
c57f56b7 1391 delete coll;
a2f5fc01 1392 if (useTags) msg += " using_tags: Yes";
c57f56b7 1393 else msg += " using_tags: No";
1394 Info("CheckDataType", msg.Data());
1395 return;
1396 }
a2f5fc01 1397 useTags = slfn.Contains(".tag");
c57f56b7 1398 if (slfn.Contains(".root")) msg += " type: root file;";
f866cba5 1399 else msg += " type: unknown file;";
a2f5fc01 1400 if (useTags) msg += " using_tags: Yes";
c57f56b7 1401 else msg += " using_tags: No";
1402 Info("CheckDataType", msg.Data());
1403}
1404
4e5c5506 1405//______________________________________________________________________________
1406void AliAnalysisAlien::EnablePackage(const char *package)
1407{
1408// Enables a par file supposed to exist in the current directory.
1409 TString pkg(package);
1410 pkg.ReplaceAll(".par", "");
1411 pkg += ".par";
1412 if (gSystem->AccessPathName(pkg)) {
ebcdf05e 1413 Fatal("EnablePackage", "Package %s not found", pkg.Data());
4e5c5506 1414 return;
1415 }
1416 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1417 Info("EnablePackage", "AliEn plugin will use .par packages");
1418 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1419 if (!fPackages) {
1420 fPackages = new TObjArray();
1421 fPackages->SetOwner();
1422 }
1423 fPackages->Add(new TObjString(pkg));
1424}
1425
d2a409b2 1426//______________________________________________________________________________
1427const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1428{
1429// Get job status for all jobs with jobid>jobidstart.
1430 static char mstatus[20];
1431 mstatus[0] = '\0';
1432 nrunning = 0;
1433 nwaiting = 0;
1434 nerror = 0;
1435 ndone = 0;
1436 TGridJobStatusList *list = gGrid->Ps("");
1437 if (!list) return mstatus;
1438 Int_t nentries = list->GetSize();
1439 TGridJobStatus *status;
1440 Int_t pid;
1441 for (Int_t ijob=0; ijob<nentries; ijob++) {
1442 status = (TGridJobStatus *)list->At(ijob);
1443 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1444 if (pid<jobidstart) continue;
1445 if (pid == lastid) {
1446 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1447 }
1448 switch (status->GetStatus()) {
1449 case TGridJobStatus::kWAITING:
1450 nwaiting++; break;
1451 case TGridJobStatus::kRUNNING:
1452 nrunning++; break;
1453 case TGridJobStatus::kABORTED:
1454 case TGridJobStatus::kFAIL:
1455 case TGridJobStatus::kUNKNOWN:
1456 nerror++; break;
1457 case TGridJobStatus::kDONE:
1458 ndone++;
1459 }
1460 }
1461 list->Delete();
1462 delete list;
1463 return mstatus;
1464}
1465
c57f56b7 1466//______________________________________________________________________________
1467Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1468{
1469// Returns true if file is a collection. Functionality duplicated from
1470// TAlien::Type() because we don't want to directly depend on TAlien.
1471 if (!gGrid) {
1472 Error("IsCollection", "No connection to grid");
1473 return kFALSE;
1474 }
1475 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1476 if (!res) return kFALSE;
1477 const char* typeStr = res->GetKey(0, "type");
1478 if (!typeStr || !strlen(typeStr)) return kFALSE;
1479 if (!strcmp(typeStr, "collection")) return kTRUE;
1480 delete res;
1481 return kFALSE;
1482}
1483
fe2d7fc2 1484//______________________________________________________________________________
1485Bool_t AliAnalysisAlien::IsSingleOutput() const
1486{
1487// Check if single-ouput option is on.
1488 return (!fOutputSingle.IsNull());
1489}
1490
16a4353c 1491//______________________________________________________________________________
1492void AliAnalysisAlien::Print(Option_t *) const
1493{
1494// Print current plugin settings.
84fcd93f 1495 printf("### AliEn analysis plugin current settings ###\n");
e1c22e21 1496 printf("= OverwriteMode:________________________________ %d\n", fOverwriteMode);
1497 if (fOverwriteMode) {
1498 printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
1499 \n***** To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
1500 }
348be253 1501 printf("= Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
1502 printf("= Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
84fcd93f 1503 printf("= Production mode:______________________________ %d\n", fProductionMode);
1504 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1505 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1506 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
16a4353c 1507 if (fUser.Length())
84fcd93f 1508 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1509 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1510 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1511 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1512 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1513 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
16a4353c 1514 if (fRunNumbers.Length())
84fcd93f 1515 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
16a4353c 1516 if (fRunRange[0])
5fce53f4 1517 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
16a4353c 1518 if (!fRunRange[0] && !fRunNumbers.Length()) {
1519 TIter next(fInputFiles);
1520 TObject *obj;
1521 TString list;
1522 while ((obj=next())) list += obj->GetName();
84fcd93f 1523 printf("= Input files to be processed: _________________ %s\n", list.Data());
16a4353c 1524 }
1525 if (TestBit(AliAnalysisGrid::kTest))
84fcd93f 1526 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1527 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1528 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1529 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1530 printf("=====================================================================\n");
1531 printf("= Job price: ___________________________________ %d\n", fPrice);
1532 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1533 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
16a4353c 1534 if (fMaxInitFailed>0)
84fcd93f 1535 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
16a4353c 1536 if (fMasterResubmitThreshold>0)
84fcd93f 1537 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
149d288c 1538 printf("= Number of replicas for the output files_______ %d\n", fNreplicas);
319593fb 1539 if (fNrunsPerMaster>0)
84fcd93f 1540 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1541 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
b5b9dee8 1542 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1543 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
16a4353c 1544 if (fArguments.Length())
84fcd93f 1545 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
631c0b05 1546 if (fExecutableArgs.Length())
1547 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
84fcd93f 1548 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1549 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1550 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1551 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
16a4353c 1552 if (fDatasetName)
84fcd93f 1553 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1554 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
16a4353c 1555 if (fIncludePath.Data())
84fcd93f 1556 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
16a4353c 1557 if (fCloseSE.Length())
84fcd93f 1558 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
16a4353c 1559 if (fFriendChainName.Length())
84fcd93f 1560 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
16a4353c 1561 if (fPackages) {
1562 TIter next(fPackages);
1563 TObject *obj;
1564 TString list;
1565 while ((obj=next())) list += obj->GetName();
84fcd93f 1566 printf("= Par files to be used: ________________________ %s\n", list.Data());
16a4353c 1567 }
1568}
1569
c57f56b7 1570//______________________________________________________________________________
1571void AliAnalysisAlien::SetDefaults()
1572{
1573// Set default values for everything. What cannot be filled will be left empty.
1574 if (fGridJDL) delete fGridJDL;
1575 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
0f389141 1576 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
c57f56b7 1577 fPrice = 1;
1578 fTTL = 30000;
1579 fSplitMaxInputFileNumber = 100;
1580 fMaxInitFailed = 0;
1581 fMasterResubmitThreshold = 0;
bb885a9e 1582 fNtestFiles = 10;
149d288c 1583 fNreplicas = 2;
a8739e8a 1584 fRunRange[0] = 0;
1585 fRunRange[1] = 0;
319593fb 1586 fNrunsPerMaster = 1;
16a4353c 1587 fMaxMergeFiles = 100;
c57f56b7 1588 fRunNumbers = "";
1589 fExecutable = "analysis.sh";
0a1c1f7f 1590 fExecutableCommand = "root -b -q";
c57f56b7 1591 fArguments = "";
631c0b05 1592 fExecutableArgs = "";
c57f56b7 1593 fAnalysisMacro = "myAnalysis.C";
1594 fAnalysisSource = "";
1595 fAdditionalLibs = "";
1596 fSplitMode = "se";
1597 fAPIVersion = "";
1598 fROOTVersion = "";
1599 fAliROOTVersion = "";
1600 fUser = ""; // Your alien user name
1601 fGridWorkingDir = "";
1602 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1603 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
0df6ccf2 1604 fFriendChainName = "";
c57f56b7 1605 fGridOutputDir = "output";
149d288c 1606 fOutputArchive = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
c57f56b7 1607 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1608 fInputFormat = "xml-single";
1609 fJDLName = "analysis.jdl";
c6cb3634 1610 fJobTag = "Automatically generated analysis JDL";
bb885a9e 1611 fMergeExcludes = "";
0f389141 1612 fMergeViaJDL = 0;
348be253 1613 SetUseCopy(kTRUE);
1614 SetCheckCopy(kTRUE);
149d288c 1615 SetDefaultOutputs(kTRUE);
e1c22e21 1616 fOverwriteMode = 1;
c57f56b7 1617}
1618
0f389141 1619//______________________________________________________________________________
7c2cd90a 1620Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, Bool_t submit, const char *jdl)
0f389141 1621{
7c2cd90a 1622// Static method that checks the status of merging. This can submit merging jobs that did not produced the expected
1623// output. If <submit> is false (checking) returns true only when the final merged file was found. If submit is true returns
1624// true if the jobs were successfully submitted.
1625 Int_t countOrig = 0;
1626 Int_t countStage = 0;
1627 Int_t stage = 0;
1628 Int_t i;
1629 Bool_t doneFinal = kFALSE;
1630 TBits chunksDone;
1631 TString saliendir(aliendir);
1632 TString sfilename, stmp;
1633 saliendir.ReplaceAll("//","/");
1634 saliendir = saliendir.Strip(TString::kTrailing, '/');
1635 if (!gGrid) {
1636 ::Error("GetNregisteredFiles", "You need to be connected to AliEn.");
1637 return kFALSE;
1638 }
1639 printf("Checking directory <%s> for merged files <%s*> ...\n", aliendir, filename);
1640 TString command = Form("find %s/ *%s", saliendir.Data(), filename);
1641 TGridResult *res = gGrid->Command(command);
1642 if (!res) {
1643 ::Error("GetNregisteredFiles","Error: No result for the find command\n");
1644 return kFALSE;
1645 }
1646 TIter nextmap(res);
1647 TMap *map = 0;
1648 while ((map=(TMap*)nextmap())) {
1649 TString turl = map->GetValue("turl")->GetName();
1650 if (!turl.Length()) {
1651 // Nothing found
1652 delete res;
1653 return kFALSE;
1654 }
1655 turl.ReplaceAll("alien://", "");
1656 turl.ReplaceAll(saliendir, "");
1657 sfilename = gSystem->BaseName(turl);
1658 // Now check to what the file corresponds to:
1659 // original output - aliendir/%03d/filename
1660 // merged file (which stage) - aliendir/filename-Stage%02d_%04d
1661 // final merged file - aliendir/filename
1662 if (sfilename == turl) {
1663 if (sfilename == filename) {
1664 doneFinal = kTRUE;
1665 } else {
1666 // check stage
1667 Int_t index = sfilename.Index("Stage");
1668 if (index<0) continue;
1669 stmp = sfilename(index+5,2);
1670 Int_t istage = atoi(stmp);
1671 stmp = sfilename(index+8,4);
1672 Int_t ijob = atoi(stmp);
1673 if (istage<stage) continue; // Ignore lower stages
1674 if (istage>stage) {
1675 countStage = 0;
1676 chunksDone.ResetAllBits();
1677 stage = istage;
1678 }
1679 countStage++;
1680 chunksDone.SetBitNumber(ijob);
1681 }
1682 } else {
1683 countOrig++;
1684 }
1685 if (doneFinal) {
1686 delete res;
1687 return kTRUE;
1688 }
1689 }
1690 delete res;
1691 // Compute number of jobs that were submitted for the current stage
1692 Int_t ntotstage = countOrig;
7ae54d70 1693 for (i=1; i<=stage; i++) {
1694 if (ntotstage%nperchunk) ntotstage = (ntotstage/nperchunk)+1;
1695 else ntotstage = (ntotstage/nperchunk);
1696 }
7c2cd90a 1697 // Now compare with the number of set bits in the chunksDone array
1698 Int_t nmissing = (stage>0)?(ntotstage - countStage):0;
1699 // Print the info
1700 printf("*** Found %d original files\n", countOrig);
1701 if (stage==0) printf("*** No merging completed so far.\n");
1702 else printf("*** Found %d out of %d files merged for stage %d\n", countStage, ntotstage, stage);
1703 if (nmissing) printf("*** Number of merged files missing for this stage: %d -> check merging job completion\n", nmissing);
1704
1705 if (!submit) return doneFinal;
1706 // Sumbit merging jobs for all missing chunks for the current stage.
1707 TString query = Form("submit %s %s", jdl, aliendir);
1708 Int_t ichunk = -1;
1709 if (nmissing) {
1710 for (i=0; i<nmissing; i++) {
1711 ichunk = chunksDone.FirstNullBit(ichunk+1);
1712 Int_t jobId = SubmitSingleJob(Form("%s %d %d", query.Data(), stage, ichunk));
1713 if (!jobId) return kFALSE;
1714 }
1715 return kTRUE;
1716 }
1717 // Submit next stage of merging
1718 if (stage==0) countStage = countOrig;
7ae54d70 1719 Int_t nchunks = (countStage/nperchunk);
1720 if (countStage%nperchunk) nchunks += 1;
7c2cd90a 1721 for (i=0; i<nchunks; i++) {
1722 Int_t jobId = SubmitSingleJob(Form("%s %d %d", query.Data(), stage+1, i));
1723 if (!jobId) return kFALSE;
1724 }
1725 return kTRUE;
1726}
1727
1728//______________________________________________________________________________
1729Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
1730{
1731// Submits a single job corresponding to the query and returns job id. If 0 submission failed.
1732 if (!gGrid) return 0;
1733 printf("=> %s ------> ",query);
1734 TGridResult *res = gGrid->Command(query);
1735 if (!res) return 0;
1736 TString jobId = res->GetKey(0,"jobId");
1737 delete res;
1738 if (jobId.IsNull()) {
1739 printf("submission failed. Reason:\n");
1740 gGrid->Stdout();
1741 gGrid->Stderr();
1742 ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
1743 return 0;
1744 }
1745 printf(" Job id: %s\n", jobId.Data());
1746 return atoi(jobId);
1747}
1748
1749//______________________________________________________________________________
1750Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage, Int_t ichunk)
1751{
1752// Merge given output files from basedir. The file merger will merge nmaxmerge
1753// files in a group. Merging can be done in stages:
1754// stage=0 : will merge all existing files in a single stage
1755// stage=1 : does a find command for all files that do NOT contain the string "Stage".
1756// If their number is bigger that nmaxmerge, only the files from
1757// ichunk*nmaxmerge to ichunk*(nmaxmerge+1)-1 will get merged as output_stage_<ichunk>
1758// stage=n : does a find command for files named <output>Stage<stage-1>_*. If their number is bigger than
1759// nmaxmerge, merge just the chunk ichunk, otherwise write the merged output to the file
1760// named <output>.
a2f5fc01 1761 TString outputFile = output;
0f389141 1762 TString command;
a2f5fc01 1763 TString outputChunk;
1764 TString previousChunk = "";
1765 Int_t countChunk = 0;
1766 Int_t countZero = nmaxmerge;
0f389141 1767 Bool_t merged = kTRUE;
a2f5fc01 1768 Int_t index = outputFile.Index("@");
1769 if (index > 0) outputFile.Remove(index);
7c2cd90a 1770 TString inputFile = outputFile;
1771 if (stage>1) inputFile.ReplaceAll(".root", Form("-Stage%02d_*.root", stage-1));
1772 command = Form("find %s/ *%s", basedir, inputFile.Data());
0f389141 1773 printf("command: %s\n", command.Data());
1774 TGridResult *res = gGrid->Command(command);
1775 if (!res) {
7c2cd90a 1776 ::Error("MergeOutput","No result for the find command\n");
0f389141 1777 return kFALSE;
1778 }
1779
1780 TFileMerger *fm = 0;
1781 TIter nextmap(res);
1782 TMap *map = 0;
7c2cd90a 1783 // Check if there is a merge operation to resume. Works only for stage 0 or 1.
a2f5fc01 1784 outputChunk = outputFile;
1785 outputChunk.ReplaceAll(".root", "_*.root");
0f389141 1786 // Check for existent temporary merge files
e1c22e21 1787 // Check overwrite mode and remove previous partial results if needed
7c2cd90a 1788 // Preserve old merging functionality for stage 0.
1789 if (stage==0) {
1790 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
1791 while (1) {
1792 // Skip as many input files as in a chunk
1793 for (Int_t counter=0; counter<nmaxmerge; counter++) map = (TMap*)nextmap();
1794 if (!map) {
1795 ::Error("MergeOutput", "Cannot resume merging for <%s>, nentries=%d", outputFile.Data(), res->GetSize());
1796 delete res;
1797 return kFALSE;
1798 }
1799 outputChunk = outputFile;
1800 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
1801 countChunk++;
1802 if (gSystem->AccessPathName(outputChunk)) continue;
1803 // Merged file with chunks up to <countChunk> found
1804 ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
1805 previousChunk = outputChunk;
1806 break;
1807 }
1808 }
1809 countZero = nmaxmerge;
1810
1811 while ((map=(TMap*)nextmap())) {
1812 // Loop 'find' results and get next LFN
1813 if (countZero == nmaxmerge) {
1814 // First file in chunk - create file merger and add previous chunk if any.
1815 fm = new TFileMerger(kFALSE);
1816 fm->SetFastMethod(kTRUE);
1817 if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
1818 outputChunk = outputFile;
1819 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
1820 }
1821 // If last file found, put merged results in the output file
1822 if (map == res->Last()) outputChunk = outputFile;
1823 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1824 if (!objs || !objs->GetString().Length()) {
1825 // Nothing found - skip this output
0f389141 1826 delete res;
7c2cd90a 1827 delete fm;
0f389141 1828 return kFALSE;
7c2cd90a 1829 }
1830 // Add file to be merged and decrement chunk counter.
1831 fm->AddFile(objs->GetString());
1832 countZero--;
1833 if (countZero==0 || map == res->Last()) {
1834 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1835 // Nothing found - skip this output
1836 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
1837 delete res;
1838 delete fm;
1839 return kFALSE;
1840 }
1841 fm->OutputFile(outputChunk);
1842 // Merge the outputs, then go to next chunk
1843 if (!fm->Merge()) {
1844 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
1845 delete res;
1846 delete fm;
1847 return kFALSE;
1848 } else {
1849 ::Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
1850 gSystem->Unlink(previousChunk);
1851 }
1852 if (map == res->Last()) {
1853 delete res;
1854 delete fm;
1855 break;
1856 }
1857 countChunk++;
1858 countZero = nmaxmerge;
1859 previousChunk = outputChunk;
0f389141 1860 }
0f389141 1861 }
7c2cd90a 1862 return merged;
1863 }
1864 // Merging stage different than 0.
1865 // Move to the begining of the requested chunk.
1866 outputChunk = outputFile;
1867 if (nmaxmerge < res->GetSize()) {
1868 if (ichunk*nmaxmerge >= res->GetSize()) {
1869 ::Error("MergeOutput", "Cannot merge merge chunk %d grouping %d files from %d total.", ichunk, nmaxmerge, res->GetSize());
1870 delete res;
1871 return kFALSE;
1872 }
1873 for (Int_t counter=0; counter<ichunk*nmaxmerge; counter++) map = (TMap*)nextmap();
1874 outputChunk.ReplaceAll(".root", Form("-Stage%02d_%04d.root", stage, ichunk));
1875 }
1876 countZero = nmaxmerge;
1877 fm = new TFileMerger(kFALSE);
1878 fm->SetFastMethod(kTRUE);
0f389141 1879 while ((map=(TMap*)nextmap())) {
7c2cd90a 1880 // Loop 'find' results and get next LFN
0f389141 1881 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1882 if (!objs || !objs->GetString().Length()) {
1883 // Nothing found - skip this output
1884 delete res;
1885 delete fm;
1886 return kFALSE;
1887 }
1888 // Add file to be merged and decrement chunk counter.
1889 fm->AddFile(objs->GetString());
a2f5fc01 1890 countZero--;
7c2cd90a 1891 if (countZero==0) break;
1892 }
1893 delete res;
1894 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1895 // Nothing found - skip this output
1896 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
1897 delete fm;
1898 return kFALSE;
1899 }
1900 fm->OutputFile(outputChunk);
1901 // Merge the outputs
1902 if (!fm->Merge()) {
1903 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
1904 delete fm;
1905 return kFALSE;
1906 } else {
1907 ::Info("MergeOutput", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
0f389141 1908 }
7c2cd90a 1909 delete fm;
1910 return kTRUE;
0f389141 1911}
1912
c57f56b7 1913//______________________________________________________________________________
1914Bool_t AliAnalysisAlien::MergeOutputs()
1915{
1916// Merge analysis outputs existing in the AliEn space.
1917 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1918 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1919 if (!Connect()) {
1920 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1921 return kFALSE;
0f389141 1922 }
c9e8f7fd 1923 if (fMergeViaJDL) {
1924 if (!TestBit(AliAnalysisGrid::kMerge)) {
1925 Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
1926 return kFALSE;
1927 }
1928 if (fProductionMode) {
1929 Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
1930 return kFALSE;
1931 }
0f389141 1932 Info("MergeOutputs", "Submitting merging JDL");
a03be957 1933 if (!SubmitMerging()) return kFALSE;
0f389141 1934 Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
c9e8f7fd 1935 Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
001cb79e 1936 return kFALSE;
c57f56b7 1937 }
1938 // Get the output path
d2a409b2 1939 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
923e2ca5 1940 if (!DirectoryExists(fGridOutputDir)) {
c57f56b7 1941 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1942 return kFALSE;
1943 }
1944 if (!fOutputFiles.Length()) {
1945 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1946 return kFALSE;
0f389141 1947 }
1948 // Check if fast read option was requested
e1c22e21 1949 Info("MergeOutputs", "Started local merging of output files from: alien://%s \
1950 \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
0f389141 1951 if (fFastReadOption) {
d3339be3 1952 Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
1953 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
1954 gEnv->SetValue("XNet.ConnectTimeout",10);
1955 gEnv->SetValue("XNet.RequestTimeout",10);
0f389141 1956 gEnv->SetValue("XNet.MaxRedirectCount",2);
d3339be3 1957 gEnv->SetValue("XNet.ReconnectTimeout",10);
0f389141 1958 gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
c57f56b7 1959 }
e8b839ab 1960 // Make sure we change the temporary directory
1961 gSystem->Setenv("TMPDIR", gSystem->pwd());
149d288c 1962 TObjArray *list = fOutputFiles.Tokenize(",");
c57f56b7 1963 TIter next(list);
1964 TObjString *str;
a2f5fc01 1965 TString outputFile;
c57f56b7 1966 Bool_t merged = kTRUE;
1967 while((str=(TObjString*)next())) {
a2f5fc01 1968 outputFile = str->GetString();
1969 Int_t index = outputFile.Index("@");
1970 if (index > 0) outputFile.Remove(index);
1971 TString outputChunk = outputFile;
1972 outputChunk.ReplaceAll(".root", "_*.root");
319593fb 1973 // Skip already merged outputs
a2f5fc01 1974 if (!gSystem->AccessPathName(outputFile)) {
e1c22e21 1975 if (fOverwriteMode) {
a2f5fc01 1976 Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
1977 gSystem->Unlink(outputFile);
1978 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
e1c22e21 1979 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
a2f5fc01 1980 outputChunk.Data());
1981 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
e1c22e21 1982 }
1983 } else {
a2f5fc01 1984 Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
e1c22e21 1985 continue;
1986 }
1987 } else {
a2f5fc01 1988 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
e1c22e21 1989 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
a2f5fc01 1990 outputChunk.Data());
1991 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
e1c22e21 1992 }
1993 }
bb885a9e 1994 if (fMergeExcludes.Length() &&
a2f5fc01 1995 fMergeExcludes.Contains(outputFile.Data())) continue;
16a4353c 1996 // Perform a 'find' command in the output directory, looking for registered outputs
a2f5fc01 1997 merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
0f389141 1998 if (!merged) {
1999 Error("MergeOutputs", "Terminate() will NOT be executed");
2000 return kFALSE;
ff07ec61 2001 }
2002 TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2003 if (fileOpened) fileOpened->Close();
c57f56b7 2004 }
0f389141 2005 return kTRUE;
c57f56b7 2006}
2007
bb885a9e 2008//______________________________________________________________________________
2009void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2010{
2011// Use the output files connected to output containers from the analysis manager
2012// rather than the files defined by SetOutputFiles
2013 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
205b201f 2014 Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
bb885a9e 2015 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2016}
2017
149d288c 2018//______________________________________________________________________________
2019void AliAnalysisAlien::SetOutputFiles(const char *list)
2020{
2021// Manually set the output files list.
2022// Removes duplicates. Not allowed if default outputs are not disabled.
2023 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2024 Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2025 return;
2026 }
2027 Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2028 fOutputFiles = "";
2029 TString slist = list;
2030 if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2031 TObjArray *arr = slist.Tokenize(" ");
2032 TObjString *os;
2033 TIter next(arr);
2034 TString sout;
2035 while ((os=(TObjString*)next())) {
2036 sout = os->GetString();
2037 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2038 if (fOutputFiles.Contains(sout)) continue;
2039 if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2040 fOutputFiles += sout;
2041 }
2042 delete arr;
2043}
2044
2045//______________________________________________________________________________
2046void AliAnalysisAlien::SetOutputArchive(const char *list)
2047{
2048// Manually set the output archive list. Free text - you are on your own...
2049// Not allowed if default outputs are not disabled.
2050 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2051 Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2052 return;
2053 }
2054 Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2055 fOutputArchive = list;
2056}
2057
2058//______________________________________________________________________________
2059void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2060{
2061// Setting a prefered output SE is not allowed anymore.
2062 Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2063}
2064
5513444a 2065//______________________________________________________________________________
2066Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
c57f56b7 2067{
2068// Start remote grid analysis.
2069
43da816a 2070 // Check if output files have to be taken from the analysis manager
2071 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2072 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2073 if (!mgr || !mgr->IsInitialized()) {
2074 Error("StartAnalysis", "You need an initialized analysis manager for this");
5513444a 2075 return kFALSE;
43da816a 2076 }
2077 fOutputFiles = "";
2078 TIter next(mgr->GetOutputs());
2079 AliAnalysisDataContainer *output;
2080 while ((output=(AliAnalysisDataContainer*)next())) {
2081 const char *filename = output->GetFileName();
2082 if (!(strcmp(filename, "default"))) {
2083 if (!mgr->GetOutputEventHandler()) continue;
2084 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
2085 }
84fcd93f 2086 if (fOutputFiles.Contains(filename)) continue;
149d288c 2087 if (fOutputFiles.Length()) fOutputFiles += ",";
43da816a 2088 fOutputFiles += filename;
2089 }
c07b9ce2 2090 // Add extra files registered to the analysis manager
2091 if (mgr->GetExtraFiles().Length()) {
149d288c 2092 if (fOutputFiles.Length()) fOutputFiles += ",";
2093 TString extra = mgr->GetExtraFiles();
2094 extra.ReplaceAll(" ", ",");
2095 // Protection in case extra files do not exist (will it work?)
2096 extra.ReplaceAll(".root", "*.root");
2097 fOutputFiles += extra;
84fcd93f 2098 }
149d288c 2099 // Compose the output archive.
2100 fOutputArchive = "log_archive.zip:std*@disk=1 ";
2101 fOutputArchive += Form("root_archive.zip:%s@disk=%d",fOutputFiles.Data(),fNreplicas);
43da816a 2102 }
f7b1cbc2 2103// if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
c57f56b7 2104 if (TestBit(AliAnalysisGrid::kOffline)) {
2105 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2106 \n there nor any job run. You can revise the JDL and analysis \
2107 \n macro then run the same in \"submit\" mode.");
2108 } else if (TestBit(AliAnalysisGrid::kTest)) {
2109 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
2110 \n dataset.");
2111 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2112 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
2113 \n space and job submitted.");
2114 } else if (TestBit(AliAnalysisGrid::kMerge)) {
2115 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
0f389141 2116 if (fMergeViaJDL) CheckInputData();
5513444a 2117 return kTRUE;
c57f56b7 2118 } else {
2119 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
2120 }
2121
348be253 2122 Print();
c57f56b7 2123 if (!Connect()) {
2124 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
5513444a 2125 return kFALSE;
16a4353c 2126 }
348be253 2127 if (IsCheckCopy()) CheckFileCopy(gGrid->GetHomeDirectory());
c57f56b7 2128 if (!CheckInputData()) {
2129 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
5513444a 2130 return kFALSE;
c57f56b7 2131 }
d3339be3 2132 if (!CreateDataset(fDataPattern)) {
2133 TString serror;
2134 if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2135 if (fRunNumbers.Length()) serror = "run numbers";
2136 if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2137 serror += Form("\n or data pattern <%s>", fDataPattern.Data());
2138 Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2139 return kFALSE;
2140 }
c57f56b7 2141 WriteAnalysisFile();
2142 WriteAnalysisMacro();
2143 WriteExecutable();
2144 WriteValidationScript();
0f389141 2145 if (fMergeViaJDL) {
2146 WriteMergingMacro();
2147 WriteMergeExecutable();
2148 WriteValidationScript(kTRUE);
2149 }
5513444a 2150 if (!CreateJDL()) return kFALSE;
2151 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
c57f56b7 2152 if (TestBit(AliAnalysisGrid::kTest)) {
2153 // Locally testing the analysis
2154 Info("StartAnalysis", "\n_______________________________________________________________________ \
2155 \n Running analysis script in a daughter shell as on a worker node \
2156 \n_______________________________________________________________________");
149d288c 2157 TObjArray *list = fOutputFiles.Tokenize(",");
c57f56b7 2158 TIter next(list);
2159 TObjString *str;
a2f5fc01 2160 TString outputFile;
c57f56b7 2161 while((str=(TObjString*)next())) {
a2f5fc01 2162 outputFile = str->GetString();
2163 Int_t index = outputFile.Index("@");
2164 if (index > 0) outputFile.Remove(index);
2165 if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
c57f56b7 2166 }
2167 delete list;
2168 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
0d5d317c 2169 TString validationScript = fExecutable;
2170 validationScript.ReplaceAll(".sh", "_validation.sh");
2171 gSystem->Exec(Form("bash %s",validationScript.Data()));
c57f56b7 2172// gSystem->Exec("cat stdout");
5513444a 2173 return kFALSE;
c57f56b7 2174 }
5513444a 2175 // Check if submitting is managed by LPM manager
a3e84053 2176 if (fProductionMode) {
5513444a 2177 TString prodfile = fJDLName;
2178 prodfile.ReplaceAll(".jdl", ".prod");
2179 WriteProductionFile(prodfile);
2180 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2181 return kFALSE;
2182 }
a8739e8a 2183 // Submit AliEn job(s)
d2a409b2 2184 gGrid->Cd(fGridOutputDir);
a8739e8a 2185 TGridResult *res;
c57f56b7 2186 TString jobID = "";
d2a409b2 2187 if (!fRunNumbers.Length() && !fRunRange[0]) {
dd74a515 2188 // Submit a given xml or a set of runs
a8739e8a 2189 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
84fcd93f 2190 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
a8739e8a 2191 if (res) {
2192 const char *cjobId = res->GetKey(0,"jobId");
2193 if (!cjobId) {
a03be957 2194 gGrid->Stdout();
2195 gGrid->Stderr();
a8739e8a 2196 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
5513444a 2197 return kFALSE;
a8739e8a 2198 } else {
2199 Info("StartAnalysis", "\n_______________________________________________________________________ \
2200 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2201 \n_______________________________________________________________________",
2202 fJDLName.Data(), cjobId);
2203 jobID = cjobId;
2204 }
2205 delete res;
a03be957 2206 } else {
2207 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2208 return kFALSE;
a8739e8a 2209 }
2210 } else {
d2a409b2 2211 // Submit for a range of enumeration of runs.
a03be957 2212 if (!Submit()) return kFALSE;
c57f56b7 2213 }
a8739e8a 2214
c57f56b7 2215 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2216 \n You may exit at any time and terminate the job later using the option <terminate> \
2217 \n ##################################################################################", jobID.Data());
bb885a9e 2218 gSystem->Exec("aliensh");
5513444a 2219 return kTRUE;
c57f56b7 2220}
2221
d2a409b2 2222//______________________________________________________________________________
a03be957 2223Bool_t AliAnalysisAlien::Submit()
d2a409b2 2224{
2225// Submit all master jobs.
2226 Int_t nmasterjobs = fInputFiles->GetEntries();
2227 Long_t tshoot = gSystem->Now();
a03be957 2228 if (!fNsubmitted && !SubmitNext()) return kFALSE;
d2a409b2 2229 while (fNsubmitted < nmasterjobs) {
2230 Long_t now = gSystem->Now();
2231 if ((now-tshoot)>30000) {
2232 tshoot = now;
a03be957 2233 if (!SubmitNext()) return kFALSE;
d2a409b2 2234 }
2235 }
a03be957 2236 return kTRUE;
d2a409b2 2237}
2238
0f389141 2239//______________________________________________________________________________
a03be957 2240Bool_t AliAnalysisAlien::SubmitMerging()
0f389141 2241{
2242// Submit all merging jobs.
2243 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2244 gGrid->Cd(fGridOutputDir);
2245 TString mergeJDLName = fExecutable;
2246 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2247 Int_t ntosubmit = fInputFiles->GetEntries();
0f389141 2248 for (Int_t i=0; i<ntosubmit; i++) {
f866cba5 2249 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2250 runOutDir.ReplaceAll(".xml", "");
7c2cd90a 2251 if (fOutputToRunNo) {
2252 // The output directory is the run number
2253 printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
2254 runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
2255 } else {
2256 // The output directory is the master number in 3 digits format
2257 printf("### Submitting merging job for master <%03d>\n", i);
2258 runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
2259 }
2260 // Check now the number of merging stages.
2261 TString outputFile = fOutputFiles;
2262 Int_t index = outputFile.Index(",");
2263 if (index>0) outputFile.Remove(index);
2264 Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, kTRUE, mergeJDLName);
2265 if (!done) return kFALSE;
0f389141 2266 }
a03be957 2267 if (!ntosubmit) return kTRUE;
0f389141 2268 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
2269 \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
2270 \n ##################################################################################");
2271 gSystem->Exec("aliensh");
a03be957 2272 return kTRUE;
0f389141 2273}
2274
d2a409b2 2275//______________________________________________________________________________
a03be957 2276Bool_t AliAnalysisAlien::SubmitNext()
d2a409b2 2277{
2278// Submit next bunch of master jobs if the queue is free.
2279 static Bool_t iscalled = kFALSE;
2280 static Int_t firstmaster = 0;
2281 static Int_t lastmaster = 0;
2282 static Int_t npermaster = 0;
a03be957 2283 if (iscalled) return kTRUE;
d2a409b2 2284 iscalled = kTRUE;
2285 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2286 Int_t ntosubmit = 0;
2287 TGridResult *res;
2288 TString jobID = "";
2289 if (!fNsubmitted) ntosubmit = 1;
2290 else {
2291 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
84fcd93f 2292 printf("=== master %d: %s\n", lastmaster, status.Data());
d2a409b2 2293 // If last master not split, just return
a03be957 2294 if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
d2a409b2 2295 // No more than 100 waiting jobs
a03be957 2296 if (nwaiting>100) {iscalled = kFALSE; return kTRUE;}
d2a409b2 2297 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
2298 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
7586eedc 2299 if (!ntosubmit) ntosubmit = 1;
84fcd93f 2300 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
d2a409b2 2301 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2302 }
2303 Int_t nmasterjobs = fInputFiles->GetEntries();
2304 for (Int_t i=0; i<ntosubmit; i++) {
2305 // Submit for a range of enumeration of runs.
a03be957 2306 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
d2a409b2 2307 TString query;
cd11251e 2308 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2309 runOutDir.ReplaceAll(".xml", "");
2310 if (fOutputToRunNo)
2311 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2312 else
2313 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
84fcd93f 2314 printf("********* %s\n",query.Data());
d2a409b2 2315 res = gGrid->Command(query);
2316 if (res) {
98ca124f 2317 TString cjobId1 = res->GetKey(0,"jobId");
2318 if (!cjobId1.Length()) {
d2a409b2 2319 iscalled = kFALSE;
a03be957 2320 gGrid->Stdout();
2321 gGrid->Stderr();
2322 Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2323 return kFALSE;
d2a409b2 2324 } else {
2325 Info("StartAnalysis", "\n_______________________________________________________________________ \
2326 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2327 \n_______________________________________________________________________",
98ca124f 2328 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
d2a409b2 2329 jobID += cjobId1;
2330 jobID += " ";
98ca124f 2331 lastmaster = cjobId1.Atoi();
d2a409b2 2332 if (!firstmaster) firstmaster = lastmaster;
2333 fNsubmitted++;
2334 }
2335 delete res;
a03be957 2336 } else {
2337 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2338 return kFALSE;
d2a409b2 2339 }
2340 }
2341 iscalled = kFALSE;
a03be957 2342 return kTRUE;
d2a409b2 2343}
2344
c57f56b7 2345//______________________________________________________________________________
2346void AliAnalysisAlien::WriteAnalysisFile()
2347{
f10e8481 2348// Write current analysis manager into the file <analysisFile>
2349 TString analysisFile = fExecutable;
2350 analysisFile.ReplaceAll(".sh", ".root");
c57f56b7 2351 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2352 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2353 if (!mgr || !mgr->IsInitialized()) {
2354 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2355 return;
2356 }
2357 // Check analysis type
2358 TObject *handler;
2359 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
2360 handler = (TObject*)mgr->GetInputEventHandler();
2361 if (handler) {
2362 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
2363 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
2364 }
2365 TDirectory *cdir = gDirectory;
f10e8481 2366 TFile *file = TFile::Open(analysisFile, "RECREATE");
c57f56b7 2367 if (file) {
e16a394c 2368 // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
2369 if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
fe2d7fc2 2370 // Unless merging makes no sense
2371 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
c57f56b7 2372 mgr->Write();
2373 delete file;
fe2d7fc2 2374 // Enable termination for local jobs
2375 mgr->SetSkipTerminate(kFALSE);
c57f56b7 2376 }
2377 if (cdir) cdir->cd();
f10e8481 2378 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
c57f56b7 2379 }
2380 Bool_t copy = kTRUE;
2381 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2382 if (copy) {
2383 CdWork();
2384 TString workdir = gGrid->GetHomeDirectory();
2385 workdir += fGridWorkingDir;
f10e8481 2386 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
2387 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
2388 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
c57f56b7 2389 }
2390}
2391
2392//______________________________________________________________________________
2393void AliAnalysisAlien::WriteAnalysisMacro()
2394{
2395// Write the analysis macro that will steer the analysis in grid mode.
2396 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2397 ofstream out;
2398 out.open(fAnalysisMacro.Data(), ios::out);
2399 if (!out.good()) {
2400 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2401 return;
2402 }
5b273635 2403 Bool_t hasSTEERBase = kFALSE;
2404 Bool_t hasESD = kFALSE;
2405 Bool_t hasAOD = kFALSE;
2406 Bool_t hasANALYSIS = kFALSE;
2407 Bool_t hasANALYSISalice = kFALSE;
2408 Bool_t hasCORRFW = kFALSE;
c57f56b7 2409 TString func = fAnalysisMacro;
2410 TString type = "ESD";
2411 TString comment = "// Analysis using ";
2412 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2413 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2414 type = "AOD";
2415 comment += "AOD";
2416 }
0df6ccf2 2417 if (type!="AOD" && fFriendChainName!="") {
2418 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2419 return;
2420 }
c57f56b7 2421 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2422 else comment += " data";
2423 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2424 func.ReplaceAll(".C", "");
2425 out << "void " << func.Data() << "()" << endl;
2426 out << "{" << endl;
2427 out << comment.Data() << endl;
2428 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
f7498086 2429 out << " TStopwatch timer;" << endl;
2430 out << " timer.Start();" << endl << endl;
c57f56b7 2431 out << "// load base root libraries" << endl;
2432 out << " gSystem->Load(\"libTree\");" << endl;
2433 out << " gSystem->Load(\"libGeom\");" << endl;
2434 out << " gSystem->Load(\"libVMC\");" << endl;
2435 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
648174cf 2436 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
d5c6455a 2437 if (fAdditionalRootLibs.Length()) {
47a4137d 2438 // in principle libtree /lib geom libvmc etc. can go into this list, too
2439 out << "// Add aditional libraries" << endl;
2440 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2441 TIter next(list);
2442 TObjString *str;
2443 while((str=(TObjString*)next())) {
2444 if (str->GetString().Contains(".so"))
2445 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
d5c6455a 2446 }
47a4137d 2447 if (list) delete list;
d5c6455a 2448 }
47a4137d 2449 out << "// include path" << endl;
2450 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2451 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
57377eb5 2452 out << "// Load analysis framework libraries" << endl;
4e5c5506 2453 if (!fPackages) {
4e5c5506 2454 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2455 out << " gSystem->Load(\"libESD\");" << endl;
2456 out << " gSystem->Load(\"libAOD\");" << endl;
2457 out << " gSystem->Load(\"libANALYSIS\");" << endl;
57377eb5 2458 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2459 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
4e5c5506 2460 } else {
4e5c5506 2461 TIter next(fPackages);
2462 TObject *obj;
57377eb5 2463 TString pkgname;
5b273635 2464 TString setupPar = "AliAnalysisAlien::SetupPar";
57377eb5 2465 while ((obj=next())) {
2466 pkgname = obj->GetName();
4478e6f1 2467 if (pkgname == "STEERBase" ||
2468 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2469 if (pkgname == "ESD" ||
2470 pkgname == "ESD.par") hasESD = kTRUE;
2471 if (pkgname == "AOD" ||
2472 pkgname == "AOD.par") hasAOD = kTRUE;
2473 if (pkgname == "ANALYSIS" ||
2474 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
2475 if (pkgname == "ANALYSISalice" ||
2476 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2477 if (pkgname == "CORRFW" ||
2478 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
5b273635 2479 }
2480 if (hasANALYSISalice) setupPar = "SetupPar";
57377eb5 2481 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
5b273635 2482 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
57377eb5 2483 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
5b273635 2484 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
57377eb5 2485 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
5b273635 2486 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
57377eb5 2487 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
5b273635 2488 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
57377eb5 2489 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
5b273635 2490 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
57377eb5 2491 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
5b273635 2492 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
57377eb5 2493 out << "// Compile other par packages" << endl;
2494 next.Reset();
fcc9bb6f 2495 while ((obj=next())) {
2496 pkgname = obj->GetName();
4478e6f1 2497 if (pkgname == "STEERBase" ||
2498 pkgname == "STEERBase.par" ||
2499 pkgname == "ESD" ||
2500 pkgname == "ESD.par" ||
2501 pkgname == "AOD" ||
2502 pkgname == "AOD.par" ||
2503 pkgname == "ANALYSIS" ||
2504 pkgname == "ANALYSIS.par" ||
2505 pkgname == "ANALYSISalice" ||
2506 pkgname == "ANALYSISalice.par" ||
2507 pkgname == "CORRFW" ||
2508 pkgname == "CORRFW.par") continue;
5b273635 2509 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
fcc9bb6f 2510 }
4e5c5506 2511 }
6da75e0b 2512 if (fAdditionalLibs.Length()) {
2513 out << "// Add aditional AliRoot libraries" << endl;
2514 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2515 TIter next(list);
2516 TObjString *str;
2517 while((str=(TObjString*)next())) {
2518 if (str->GetString().Contains(".so"))
2519 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2520 }
2521 if (list) delete list;
2522 }
2523 out << endl;
c57f56b7 2524 out << "// analysis source to be compiled at runtime (if any)" << endl;
2525 if (fAnalysisSource.Length()) {
2526 TObjArray *list = fAnalysisSource.Tokenize(" ");
2527 TIter next(list);
2528 TObjString *str;
2529 while((str=(TObjString*)next())) {
2530 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2531 }
2532 if (list) delete list;
2533 }
2534 out << endl;
0f389141 2535 if (fFastReadOption) {
d3339be3 2536 Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. This may skip some files that could be accessed !!! \
2537 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
0f389141 2538 out << "// fast xrootd reading enabled" << endl;
2539 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
d3339be3 2540 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2541 out << " gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
0f389141 2542 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
d3339be3 2543 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
0f389141 2544 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2545 }
e8b839ab 2546 // Change temp directory to current one
2547 out << "// Set temporary merging directory to current one" << endl;
2548 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
c57f56b7 2549 out << "// connect to AliEn and make the chain" << endl;
2550 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
2551 if (IsUsingTags()) {
2552 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2553 } else {
45e980c4 2554 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
c57f56b7 2555 }
2556 out << "// read the analysis manager from file" << endl;
f10e8481 2557 TString analysisFile = fExecutable;
2558 analysisFile.ReplaceAll(".sh", ".root");
2559 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
c57f56b7 2560 out << " if (!file) return;" << endl;
2561 out << " TIter nextkey(file->GetListOfKeys());" << endl;
2562 out << " AliAnalysisManager *mgr = 0;" << endl;
2563 out << " TKey *key;" << endl;
2564 out << " while ((key=(TKey*)nextkey())) {" << endl;
2565 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2566 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2567 out << " };" << endl;
2568 out << " if (!mgr) {" << endl;
205b201f 2569 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file " << analysisFile <<"\");" << endl;
c57f56b7 2570 out << " return;" << endl;
2571 out << " }" << endl << endl;
2572 out << " mgr->PrintStatus();" << endl;
52b6a92b 2573 if (AliAnalysisManager::GetAnalysisManager()) {
f866cba5 2574 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
52b6a92b 2575 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
de52b69c 2576 } else {
2577 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
52b6a92b 2578 }
2579 }
c57f56b7 2580 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
f7498086 2581 out << " timer.Stop();" << endl;
2582 out << " timer.Print();" << endl;
c57f56b7 2583 out << "}" << endl << endl;
2584 if (IsUsingTags()) {
2585 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2586 out << "{" << endl;
2587 out << "// Create a chain using tags from the xml file." << endl;
2588 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2589 out << " if (!coll) {" << endl;
2590 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2591 out << " return NULL;" << endl;
2592 out << " }" << endl;
2593 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2594 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2595 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
2596 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
2597 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
2598 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2599 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
2600 out << " // Check if the cuts configuration file was provided" << endl;
2601 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2602 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2603 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2604 out << " }" << endl;
0df6ccf2 2605 if (fFriendChainName=="") {
2606 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2607 } else {
2608 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
2609 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2610 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2611 }
c57f56b7 2612 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2613 out << " chain->ls();" << endl;
2614 out << " return chain;" << endl;
fcc9bb6f 2615 out << "}" << endl << endl;
c57f56b7 2616 if (gSystem->AccessPathName("ConfigureCuts.C")) {
2617 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
2618 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2619 msg += " AliLHCTagCuts *lhcCuts,\n";
2620 msg += " AliDetectorTagCuts *detCuts,\n";
2621 msg += " AliEventTagCuts *evCuts)";
2622 Info("WriteAnalysisMacro", msg.Data());
2623 }
0df6ccf2 2624 }
2625 if (!IsUsingTags() || fFriendChainName!="") {
fcc9bb6f 2626 out <<"//________________________________________________________________________________" << endl;
c57f56b7 2627 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2628 out << "{" << endl;
2629 out << "// Create a chain using url's from xml file" << endl;
2630 out << " TString treename = type;" << endl;
2631 out << " treename.ToLower();" << endl;
2632 out << " treename += \"Tree\";" << endl;
e02fee64 2633 out << " printf(\"***************************************\\n\");" << endl;
2634 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
2635 out << " printf(\"***************************************\\n\");" << endl;
c57f56b7 2636 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2637 out << " if (!coll) {" << endl;
2638 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2639 out << " return NULL;" << endl;
2640 out << " }" << endl;
2641 out << " TChain *chain = new TChain(treename);" << endl;
0df6ccf2 2642 if(fFriendChainName!="") {
2643 out << " TChain *chainFriend = new TChain(treename);" << endl;
2644 }
c57f56b7 2645 out << " coll->Reset();" << endl;
0df6ccf2 2646 out << " while (coll->Next()) {" << endl;
2647 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
2648 if(fFriendChainName!="") {
2649 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
2650 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2651 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2652 out << " chainFriend->Add(fileFriend.Data());" << endl;
2653 }
2654 out << " }" << endl;
c57f56b7 2655 out << " if (!chain->GetNtrees()) {" << endl;
2656 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2657 out << " return NULL;" << endl;
2658 out << " }" << endl;
0df6ccf2 2659 if(fFriendChainName!="") {
2660 out << " chain->AddFriend(chainFriend);" << endl;
2661 }
c57f56b7 2662 out << " return chain;" << endl;
fcc9bb6f 2663 out << "}" << endl << endl;
c57f56b7 2664 }
5b273635 2665 if (hasANALYSISalice) {
2666 out <<"//________________________________________________________________________________" << endl;
2667 out << "Bool_t SetupPar(const char *package) {" << endl;
2668 out << "// Compile the package and set it up." << endl;
2669 out << " TString pkgdir = package;" << endl;
2670 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2671 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2672 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2673 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2674 out << " // Check for BUILD.sh and execute" << endl;
2675 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2676 out << " printf(\"*******************************\\n\");" << endl;
2677 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2678 out << " printf(\"*******************************\\n\");" << endl;
2679 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2680 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2681 out << " gSystem->ChangeDirectory(cdir);" << endl;
2682 out << " return kFALSE;" << endl;
2683 out << " }" << endl;
2684 out << " } else {" << endl;
2685 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2686 out << " gSystem->ChangeDirectory(cdir);" << endl;
2687 out << " return kFALSE;" << endl;
2688 out << " }" << endl;
2689 out << " // Check for SETUP.C and execute" << endl;
2690 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2691 out << " printf(\"*******************************\\n\");" << endl;
2692 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2693 out << " printf(\"*******************************\\n\");" << endl;
2694 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2695 out << " } else {" << endl;
2696 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2697 out << " gSystem->ChangeDirectory(cdir);" << endl;
2698 out << " return kFALSE;" << endl;
2699 out << " }" << endl;
2700 out << " // Restore original workdir" << endl;
2701 out << " gSystem->ChangeDirectory(cdir);" << endl;
2702 out << " return kTRUE;" << endl;
2703 out << "}" << endl;
2704 }
c57f56b7 2705 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2706 }
2707 Bool_t copy = kTRUE;
2708 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2709 if (copy) {
2710 CdWork();
2711 TString workdir = gGrid->GetHomeDirectory();
2712 workdir += fGridWorkingDir;
2713 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2714 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2715 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2716 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2717 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2718 }
2719 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2720 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2721 }
2722}
2723
0f389141 2724//______________________________________________________________________________
2725void AliAnalysisAlien::WriteMergingMacro()
2726{
2727// Write a macro to merge the outputs per master job.
2728 if (!fMergeViaJDL) return;
2729 if (!fOutputFiles.Length()) {
2730 Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2731 return;
2732 }
2733 TString mergingMacro = fExecutable;
2734 mergingMacro.ReplaceAll(".sh","_merge.C");
2735 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2736 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2737 ofstream out;
2738 out.open(mergingMacro.Data(), ios::out);
2739 if (!out.good()) {
2740 Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2741 return;
2742 }
5b273635 2743 Bool_t hasSTEERBase = kFALSE;
2744 Bool_t hasESD = kFALSE;
2745 Bool_t hasAOD = kFALSE;
2746 Bool_t hasANALYSIS = kFALSE;
2747 Bool_t hasANALYSISalice = kFALSE;
2748 Bool_t hasCORRFW = kFALSE;
0f389141 2749 TString func = mergingMacro;
2750 TString comment;
2751 func.ReplaceAll(".C", "");
7c2cd90a 2752 out << "void " << func.Data() << "(const char *dir, Int_t stage=0, Int_t ichunk=0)" << endl;
0f389141 2753 out << "{" << endl;
2754 out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
2755 out << " TStopwatch timer;" << endl;
2756 out << " timer.Start();" << endl << endl;
7c2cd90a 2757 if (!fExecutableCommand.Contains("aliroot")) {
2758 out << "// load base root libraries" << endl;
2759 out << " gSystem->Load(\"libTree\");" << endl;
2760 out << " gSystem->Load(\"libGeom\");" << endl;
2761 out << " gSystem->Load(\"libVMC\");" << endl;
2762 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
2763 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
2764 }
0f389141 2765 if (fAdditionalRootLibs.Length()) {
2766 // in principle libtree /lib geom libvmc etc. can go into this list, too
2767 out << "// Add aditional libraries" << endl;
2768 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2769 TIter next(list);
2770 TObjString *str;
2771 while((str=(TObjString*)next())) {
2772 if (str->GetString().Contains(".so"))
2773 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2774 }
2775 if (list) delete list;
2776 }
2777 out << "// include path" << endl;
2778 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2779 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2780 out << "// Load analysis framework libraries" << endl;
2781 if (!fPackages) {
7c2cd90a 2782 if (!fExecutableCommand.Contains("aliroot")) {
2783 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2784 out << " gSystem->Load(\"libESD\");" << endl;
2785 out << " gSystem->Load(\"libAOD\");" << endl;
2786 }
0f389141 2787 out << " gSystem->Load(\"libANALYSIS\");" << endl;
2788 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2789 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
2790 } else {
2791 TIter next(fPackages);
2792 TObject *obj;
2793 TString pkgname;
5b273635 2794 TString setupPar = "AliAnalysisAlien::SetupPar";
0f389141 2795 while ((obj=next())) {
2796 pkgname = obj->GetName();
2797 if (pkgname == "STEERBase" ||
2798 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2799 if (pkgname == "ESD" ||
2800 pkgname == "ESD.par") hasESD = kTRUE;
2801 if (pkgname == "AOD" ||
2802 pkgname == "AOD.par") hasAOD = kTRUE;
2803 if (pkgname == "ANALYSIS" ||
2804 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
2805 if (pkgname == "ANALYSISalice" ||
2806 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2807 if (pkgname == "CORRFW" ||
2808 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
2809 }
5b273635 2810 if (hasANALYSISalice) setupPar = "SetupPar";
0f389141 2811 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
5b273635 2812 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
0f389141 2813 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
5b273635 2814 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
0f389141 2815 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
5b273635 2816 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
0f389141 2817 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
5b273635 2818 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
0f389141 2819 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
5b273635 2820 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
0f389141 2821 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
5b273635 2822 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
0f389141 2823 out << "// Compile other par packages" << endl;
2824 next.Reset();
2825 while ((obj=next())) {
2826 pkgname = obj->GetName();
2827 if (pkgname == "STEERBase" ||
2828 pkgname == "STEERBase.par" ||
2829 pkgname == "ESD" ||
2830 pkgname == "ESD.par" ||
2831 pkgname == "AOD" ||
2832 pkgname == "AOD.par" ||
2833 pkgname == "ANALYSIS" ||
2834 pkgname == "ANALYSIS.par" ||
2835 pkgname == "ANALYSISalice" ||
2836 pkgname == "ANALYSISalice.par" ||
2837 pkgname == "CORRFW" ||
2838 pkgname == "CORRFW.par") continue;
5b273635 2839 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
0f389141 2840 }
2841 }
2842 if (fAdditionalLibs.Length()) {
2843 out << "// Add aditional AliRoot libraries" << endl;
2844 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2845 TIter next(list);
2846 TObjString *str;
2847 while((str=(TObjString*)next())) {
2848 if (str->GetString().Contains(".so"))
2849 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2850 }
2851 if (list) delete list;
2852 }
2853 out << endl;
2854 out << "// Analysis source to be compiled at runtime (if any)" << endl;
2855 if (fAnalysisSource.Length()) {
2856 TObjArray *list = fAnalysisSource.Tokenize(" ");
2857 TIter next(list);
2858 TObjString *str;
2859 while((str=(TObjString*)next())) {
2860 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2861 }
2862 if (list) delete list;
2863 }
149d288c 2864 out << endl;
2865
0f389141 2866 if (fFastReadOption) {
2867 Warning("WriteMergingMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid merging jobs. Note that this may skip some files that could be accessed !!!");
2868 out << "// fast xrootd reading enabled" << endl;
2869 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
d3339be3 2870 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2871 out << " gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
0f389141 2872 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
d3339be3 2873 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
0f389141 2874 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
e8b839ab 2875 }
2876 // Change temp directory to current one
2877 out << "// Set temporary merging directory to current one" << endl;
2878 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
0f389141 2879 out << "// Connect to AliEn" << endl;
2880 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
7c2cd90a 2881 out << " Bool_t laststage = kTRUE;" << endl;
2882 out << " TString outputDir = dir;" << endl;
0f389141 2883 out << " TString outputFiles = \"" << fOutputFiles << "\";" << endl;
2884 out << " TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
1f0d1ca2 2885 out << " mergeExcludes += \"" << AliAnalysisManager::GetAnalysisManager()->GetExtraFiles() << "\";" << endl;
58268c13 2886 out << " TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
0f389141 2887 out << " TIter *iter = new TIter(list);" << endl;
2888 out << " TObjString *str;" << endl;
a2f5fc01 2889 out << " TString outputFile;" << endl;
0f389141 2890 out << " Bool_t merged = kTRUE;" << endl;
2891 out << " while((str=(TObjString*)iter->Next())) {" << endl;
a2f5fc01 2892 out << " outputFile = str->GetString();" << endl;
7c2cd90a 2893 out << " if (outputFile.Contains(\"*\")) continue;" << endl;
a2f5fc01 2894 out << " Int_t index = outputFile.Index(\"@\");" << endl;
2895 out << " if (index > 0) outputFile.Remove(index);" << endl;
0f389141 2896 out << " // Skip already merged outputs" << endl;
a2f5fc01 2897 out << " if (!gSystem->AccessPathName(outputFile)) {" << endl;
2898 out << " printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
0f389141 2899 out << " continue;" << endl;
2900 out << " }" << endl;
a2f5fc01 2901 out << " if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
7c2cd90a 2902 out << " merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage, ichunk);" << endl;
0f389141 2903 out << " if (!merged) {" << endl;
a2f5fc01 2904 out << " printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
7c2cd90a 2905 out << " return;" << endl;
0f389141 2906 out << " }" << endl;
7c2cd90a 2907 out << " // Check if this was the last stage. If yes, run terminate for the tasks." << endl;
2908 out << " if (!gSystem->AccessPathName(outputFile)) laststage = kTRUE;" << endl;
0f389141 2909 out << " }" << endl;
7c2cd90a 2910 out << " // all outputs merged, validate" << endl;
2911 out << " ofstream out;" << endl;
2912 out << " out.open(\"outputs_valid\", ios::out);" << endl;
2913 out << " out.close();" << endl;
2914 out << " // read the analysis manager from file" << endl;
f866cba5 2915 TString analysisFile = fExecutable;
2916 analysisFile.ReplaceAll(".sh", ".root");
7c2cd90a 2917 out << " if (!laststage) return;" << endl;
f866cba5 2918 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
7c2cd90a 2919 out << " if (!file) return;" << endl;
f866cba5 2920 out << " TIter nextkey(file->GetListOfKeys());" << endl;
2921 out << " AliAnalysisManager *mgr = 0;" << endl;
2922 out << " TKey *key;" << endl;
2923 out << " while ((key=(TKey*)nextkey())) {" << endl;
2924 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2925 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2926 out << " };" << endl;
2927 out << " if (!mgr) {" << endl;
2928 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2929 out << " return;" << endl;
2930 out << " }" << endl << endl;
b385fec0 2931 out << " mgr->SetSkipTerminate(kFALSE);" << endl;
f866cba5 2932 out << " mgr->PrintStatus();" << endl;
2933 if (AliAnalysisManager::GetAnalysisManager()) {
2934 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2935 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2936 } else {
2937 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2938 }
2939 }
2940 out << " mgr->StartAnalysis(\"gridterminate\");" << endl;
0f389141 2941 out << "}" << endl << endl;
5b273635 2942 if (hasANALYSISalice) {
2943 out <<"//________________________________________________________________________________" << endl;
2944 out << "Bool_t SetupPar(const char *package) {" << endl;
2945 out << "// Compile the package and set it up." << endl;
2946 out << " TString pkgdir = package;" << endl;
2947 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2948 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2949 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2950 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2951 out << " // Check for BUILD.sh and execute" << endl;
2952 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2953 out << " printf(\"*******************************\\n\");" << endl;
2954 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2955 out << " printf(\"*******************************\\n\");" << endl;
2956 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2957 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2958 out << " gSystem->ChangeDirectory(cdir);" << endl;
2959 out << " return kFALSE;" << endl;
2960 out << " }" << endl;
2961 out << " } else {" << endl;
2962 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2963 out << " gSystem->ChangeDirectory(cdir);" << endl;
2964 out << " return kFALSE;" << endl;
2965 out << " }" << endl;
2966 out << " // Check for SETUP.C and execute" << endl;
2967 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2968 out << " printf(\"*******************************\\n\");" << endl;
2969 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2970 out << " printf(\"*******************************\\n\");" << endl;
2971 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2972 out << " } else {" << endl;
2973 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2974 out << " gSystem->ChangeDirectory(cdir);" << endl;
2975 out << " return kFALSE;" << endl;
2976 out << " }" << endl;
2977 out << " // Restore original workdir" << endl;
2978 out << " gSystem->ChangeDirectory(cdir);" << endl;
2979 out << " return kTRUE;" << endl;
2980 out << "}" << endl;
2981 }
0f389141 2982 }
2983 Bool_t copy = kTRUE;
2984 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2985 if (copy) {
2986 CdWork();
2987 TString workdir = gGrid->GetHomeDirectory();
2988 workdir += fGridWorkingDir;
2989 if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
2990 Info("WriteMergingMacro", "\n##### Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
2991 TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
2992 }
2993}
2994
2995//______________________________________________________________________________
2996Bool_t AliAnalysisAlien::SetupPar(const char *package)
2997{
205b201f 2998// Compile the par file archive pointed by <package>. This must be present in the current directory.
0f389141 2999// Note that for loading the compiled library. The current directory should have precedence in
3000// LD_LIBRARY_PATH
3001 TString pkgdir = package;
3002 pkgdir.ReplaceAll(".par","");
3003 gSystem->Exec(Form("tar xvzf %s.par", pkgdir.Data()));
3004 TString cdir = gSystem->WorkingDirectory();
3005 gSystem->ChangeDirectory(pkgdir);
3006 // Check for BUILD.sh and execute
3007 if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
3008 printf("**************************************************\n");
3009 printf("*** Building PAR archive %s\n", package);
3010 printf("**************************************************\n");
3011 if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
3012 ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
3013 gSystem->ChangeDirectory(cdir);
3014 return kFALSE;
3015 }
3016 } else {
3017 ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
3018 gSystem->ChangeDirectory(cdir);
3019 return kFALSE;
3020 }
3021 // Check for SETUP.C and execute
3022 if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
3023 printf("**************************************************\n");
3024 printf("*** Setup PAR archive %s\n", package);
3025 printf("**************************************************\n");
3026 gROOT->Macro("PROOF-INF/SETUP.C");
3027 printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
3028 } else {
3029 ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
3030 gSystem->ChangeDirectory(cdir);
3031 return kFALSE;
3032 }
3033 // Restore original workdir
3034 gSystem->ChangeDirectory(cdir);
3035 return kTRUE;
3036}
3037
c57f56b7 3038//______________________________________________________________________________
3039void AliAnalysisAlien::WriteExecutable()
3040{
3041// Generate the alien executable script.
3042 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3043 ofstream out;
3044 out.open(fExecutable.Data(), ios::out);
3045 if (out.bad()) {
5513444a 3046 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
c57f56b7 3047 return;
3048 }
3049 out << "#!/bin/bash" << endl;
c57f56b7 3050 out << "echo \"=========================================\"" << endl;
3051 out << "echo \"############## PATH : ##############\"" << endl;
3052 out << "echo $PATH" << endl;
3053 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3054 out << "echo $LD_LIBRARY_PATH" << endl;
3055 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3056 out << "echo $ROOTSYS" << endl;
3057 out << "echo \"############## which root : ##############\"" << endl;
3058 out << "which root" << endl;
3059 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3060 out << "echo $ALICE_ROOT" << endl;
3061 out << "echo \"############## which aliroot : ##############\"" << endl;
3062 out << "which aliroot" << endl;
9c5ddadc 3063 out << "echo \"############## system limits : ##############\"" << endl;
3064 out << "ulimit -a" << endl;
3065 out << "echo \"############## memory : ##############\"" << endl;
3066 out << "free -m" << endl;
c57f56b7 3067 out << "echo \"=========================================\"" << endl << endl;
74a53467 3068 // Make sure we can properly compile par files
3069 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
0a1c1f7f 3070 out << fExecutableCommand << " ";
631c0b05 3071 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
9c5ddadc 3072 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
3073 out << "echo \"############## memory after: ##############\"" << endl;
3074 out << "free -m" << endl;
c57f56b7 3075 }
3076 Bool_t copy = kTRUE;
3077 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3078 if (copy) {
3079 CdWork();
3080 TString workdir = gGrid->GetHomeDirectory();
923e2ca5 3081 TString bindir = Form("%s/bin", workdir.Data());
3082 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
c57f56b7 3083 workdir += fGridWorkingDir;
3084 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
3085 if (FileExists(executable)) gGrid->Rm(executable);
3086 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
3087 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
3088 }
3089}
3090
0f389141 3091//______________________________________________________________________________
3092void AliAnalysisAlien::WriteMergeExecutable()
3093{
3094// Generate the alien executable script for the merging job.
3095 if (!fMergeViaJDL) return;
3096 TString mergeExec = fExecutable;
3097 mergeExec.ReplaceAll(".sh", "_merge.sh");
3098 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3099 ofstream out;
3100 out.open(mergeExec.Data(), ios::out);
3101 if (out.bad()) {
3102 Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
3103 return;
3104 }
3105 out << "#!/bin/bash" << endl;
3106 out << "echo \"=========================================\"" << endl;
3107 out << "echo \"############## PATH : ##############\"" << endl;
3108 out << "echo $PATH" << endl;
3109 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3110 out << "echo $LD_LIBRARY_PATH" << endl;
3111 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3112 out << "echo $ROOTSYS" << endl;
3113 out << "echo \"############## which root : ##############\"" << endl;
3114 out << "which root" << endl;
3115 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3116 out << "echo $ALICE_ROOT" << endl;
3117 out << "echo \"############## which aliroot : ##############\"" << endl;
3118 out << "which aliroot" << endl;
3119 out << "echo \"############## system limits : ##############\"" << endl;
3120 out << "ulimit -a" << endl;
3121 out << "echo \"############## memory : ##############\"" << endl;
3122 out << "free -m" << endl;
3123 out << "echo \"=========================================\"" << endl << endl;
3124 // Make sure we can properly compile par files
3125 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3126 TString mergeMacro = fExecutable;
3127 mergeMacro.ReplaceAll(".sh", "_merge.C");
7c2cd90a 3128 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2,$3)\"" << endl;
0f389141 3129 out << fExecutableCommand << " " << "$ARG" << endl;
3130 out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
3131 out << "echo \"############## memory after: ##############\"" << endl;
3132 out << "free -m" << endl;
0f389141 3133 }
3134 Bool_t copy = kTRUE;
3135 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3136 if (copy) {
3137 CdWork();
3138 TString workdir = gGrid->GetHomeDirectory();
3139 TString bindir = Form("%s/bin", workdir.Data());
3140 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
3141 workdir += fGridWorkingDir;
3142 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
3143 if (FileExists(executable)) gGrid->Rm(executable);
3144 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
3145 TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
3146 }
3147}
3148
c57f56b7 3149//______________________________________________________________________________
5513444a 3150void AliAnalysisAlien::WriteProductionFile(const char *filename) const
3151{
3152// Write the production file to be submitted by LPM manager. The format is:
f5e8c702 3153// First line: full_path_to_jdl estimated_no_subjobs_per_master
5513444a 3154// Next lines: full_path_to_dataset XXX (XXX is a string)
3155// To submit, one has to: submit jdl XXX for all lines
3156 ofstream out;
3157 out.open(filename, ios::out);
3158 if (out.bad()) {
3159 Error("WriteProductionFile", "Bad file name: %s", filename);
3160 return;
3161 }
3162 TString workdir = gGrid->GetHomeDirectory();
3163 workdir += fGridWorkingDir;
f5e8c702 3164 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
5513444a 3165 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
f5e8c702 3166 out << locjdl << " " << njobspermaster << endl;
5513444a 3167 Int_t nmasterjobs = fInputFiles->GetEntries();
3168 for (Int_t i=0; i<nmasterjobs; i++) {
409b4ada 3169 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3170 runOutDir.ReplaceAll(".xml", "");
3171 if (fOutputToRunNo)
3172 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
3173 else
3174 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
5513444a 3175 }
3176 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
fdbbc7be 3177 if (FileExists(filename)) gGrid->Rm(filename);
5513444a 3178 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
3179}
3180
3181//______________________________________________________________________________
0f389141 3182void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
c57f56b7 3183{
3184// Generate the alien validation script.
3185 // Generate the validation script
3186 TObjString *os;
0d5d317c 3187 TString validationScript = fExecutable;
0f389141 3188 if (merge) validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
3189 else validationScript.ReplaceAll(".sh", "_validation.sh");
c57f56b7 3190 if (!Connect()) {
3191 Error("WriteValidationScript", "Alien connection required");
3192 return;
3193 }
a2f5fc01 3194 TString outStream = "";
3195 if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
c57f56b7 3196 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3197 ofstream out;
0d5d317c 3198 out.open(validationScript, ios::out);
c57f56b7 3199 out << "#!/bin/bash" << endl;
3200 out << "##################################################" << endl;
3201 out << "validateout=`dirname $0`" << endl;
3202 out << "validatetime=`date`" << endl;
3203 out << "validated=\"0\";" << endl;
3204 out << "error=0" << endl;
3205 out << "if [ -z $validateout ]" << endl;
3206 out << "then" << endl;
3207 out << " validateout=\".\"" << endl;
3208 out << "fi" << endl << endl;
3209 out << "cd $validateout;" << endl;
3210 out << "validateworkdir=`pwd`;" << endl << endl;
a2f5fc01 3211 out << "echo \"*******************************************************\"" << outStream << endl;
3212 out << "echo \"* Automatically generated validation script *\"" << outStream << endl;
c57f56b7 3213 out << "" << endl;
a2f5fc01 3214 out << "echo \"* Time: $validatetime \"" << outStream << endl;
3215 out << "echo \"* Dir: $validateout\"" << outStream << endl;
3216 out << "echo \"* Workdir: $validateworkdir\"" << outStream << endl;
3217 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3218 out << "ls -la ./" << outStream << endl;
3219 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl << endl;
c57f56b7 3220 out << "##################################################" << endl;
ebec370a 3221 out << "" << endl;
3222
3223 out << "if [ ! -f stderr ] ; then" << endl;
3224 out << " error=1" << endl;
a2f5fc01 3225 out << " echo \"* ########## Job not validated - no stderr ###\" " << outStream << endl;
3226 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3227 out << "fi" << endl;
3228
b34c9f51 3229 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
3230 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
3231 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
3232 out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
3233 out << "" << endl;
3234
ebec370a 3235 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
3236 out << " error=1" << endl;
a2f5fc01 3237 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << outStream << endl;
3238 out << " echo \"$parArch\" " << outStream << endl;
3239 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3240 out << "fi" << endl;
3241
3242 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
3243 out << " error=1" << endl;
a2f5fc01 3244 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << outStream << endl;
3245 out << " echo \"$segViol\" " << outStream << endl;
3246 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3247 out << "fi" << endl;
3248
3249 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
3250 out << " error=1" << endl;
a2f5fc01 3251 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << outStream << endl;
3252 out << " echo \"$segFault\" " << outStream << endl;
3253 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3254 out << "fi" << endl;
3255
b34c9f51 3256 out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
3257 out << " error=1" << endl;
a2f5fc01 3258 out << " echo \"* ########## Job not validated - *** glibc detected *** ###\" " << outStream << endl;
3259 out << " echo \"$glibcErr\" " << outStream << endl;
3260 out << " echo \"Error = $error\" " << outStream << endl;
b34c9f51 3261 out << "fi" << endl;
3262
ebec370a 3263 // Part dedicated to the specific analyses running into the train
3264
149d288c 3265 TObjArray *arr = fOutputFiles.Tokenize(",");
c57f56b7 3266 TIter next1(arr);
a2f5fc01 3267 TString outputFile;
5b9b4998 3268 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3269 TString extra = mgr->GetExtraFiles();
c57f56b7 3270 while ((os=(TObjString*)next1())) {
7c2cd90a 3271 if (merge) break;
a2f5fc01 3272 outputFile = os->GetString();
3273 Int_t index = outputFile.Index("@");
3274 if (index > 0) outputFile.Remove(index);
3275 if (merge && fMergeExcludes.Contains(outputFile)) continue;
3276 if (extra.Contains(outputFile)) continue;
3277 if (outputFile.Contains("*")) continue;
3278 out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
c57f56b7 3279 out << " error=1" << endl;
7c2cd90a 3280 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\"" << outStream << endl;
3281 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
c57f56b7 3282 out << "fi" << endl;
3283 }
3284 delete arr;
7c2cd90a 3285 out << "if ! [ -f outputs_valid ] ; then" << endl;
3286 out << " error=1" << endl;
3287 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
3288 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
3289 out << "fi" << endl;
923e2ca5 3290
c57f56b7 3291 out << "if [ $error = 0 ] ; then" << endl;
a2f5fc01 3292 out << " echo \"* ---------------- Job Validated ------------------*\"" << outStream << endl;
149d288c 3293 if (!IsKeepLogs()) {
3294 out << " echo \"* === Logs std* will be deleted === \"" << endl;
a2f5fc01 3295 outStream = "";
149d288c 3296 out << " rm -f std*" << endl;
3297 }
c57f56b7 3298 out << "fi" << endl;
3299
a2f5fc01 3300 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3301 out << "echo \"*******************************************************\"" << outStream << endl;
c57f56b7 3302 out << "cd -" << endl;
3303 out << "exit $error" << endl;
3304 }
3305 Bool_t copy = kTRUE;
3306 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3307 if (copy) {
3308 CdWork();
3309 TString workdir = gGrid->GetHomeDirectory();
3310 workdir += fGridWorkingDir;
0d5d317c 3311 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
3312 if (FileExists(validationScript)) gGrid->Rm(validationScript);
3313 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
c57f56b7 3314 }
3315}