]> git.uio.no Git - u/mrichter/AliRoot.git/blame - ANALYSIS/AliAnalysisAlien.cxx
fix translate options
[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);
b93f8109 395 if (gGrid->Mkdir(workdir, "-p")) {
923e2ca5 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)) {
b93f8109 920 if (gGrid->Mkdir(fGridOutputDir,"-p")) {
c57f56b7 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;
0cdf65a8 1045 TString currentfile = os->GetString();
1046 currentfile.ReplaceAll(".root", "*.root");
1047 currentfile.ReplaceAll(".zip", "-Stage$2_$3.zip");
1048 if (!currentfile.Contains("@") && fCloseSE.Length())
1049 fMergingJDL->AddToOutputArchive(Form("%s@%s",currentfile.Data(), fCloseSE.Data()), comment);
0f389141 1050 else
0cdf65a8 1051 fMergingJDL->AddToOutputArchive(currentfile, comment);
0f389141 1052 first = kFALSE;
1053 }
1054 delete arr;
c57f56b7 1055 }
149d288c 1056 arr = fOutputFiles.Tokenize(",");
c57f56b7 1057 TIter next(arr);
0f389141 1058 Bool_t first = kTRUE;
1059 const char *comment = "Files to be archived";
1060 const char *comment1 = comment;
43da816a 1061 while ((os=(TObjString*)next())) {
e1eaf596 1062 // Ignore ouputs in jdl that are also in outputarchive
1063 TString sout = os->GetString();
1064 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1065 if (fOutputArchive.Contains(sout)) continue;
0f389141 1066 if (!first) comment = NULL;
43da816a 1067 if (!os->GetString().Contains("@") && fCloseSE.Length())
0f389141 1068 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
43da816a 1069 else
0f389141 1070 fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1071 first = kFALSE;
43da816a 1072 }
c57f56b7 1073 delete arr;
0f389141 1074 if (fOutputFiles.Length()) {
1075 TString outputFiles = fOutputFiles;
1076 if (!fMergeExcludes.IsNull()) {
1077 arr = fMergeExcludes.Tokenize(" ");
705adb3e 1078 TIter next1(arr);
1079 while ((os=(TObjString*)next1())) {
0f389141 1080 outputFiles.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1081 outputFiles.ReplaceAll(os->GetString(),"");
1082 }
1083 delete arr;
1084 }
1085 arr = outputFiles.Tokenize(" ");
705adb3e 1086 TIter next2(arr);
0f389141 1087 comment = comment1;
1088 first = kTRUE;
705adb3e 1089 while ((os=(TObjString*)next2())) {
0f389141 1090 // Ignore ouputs in jdl that are also in outputarchive
1091 TString sout = os->GetString();
1092 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1093 if (fOutputArchive.Contains(sout)) continue;
1094 if (!first) comment = NULL;
1095 if (!os->GetString().Contains("@") && fCloseSE.Length())
1096 fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1097 else
1098 fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1099 }
1100 delete arr;
1101 }
1102 fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1103 fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
0d5d317c 1104 TString validationScript = fExecutable;
1105 validationScript.ReplaceAll(".sh", "_validation.sh");
0f389141 1106 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1107 validationScript = fExecutable;
1108 validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
1109 fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1110 if (fMasterResubmitThreshold) {
1111 fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1112 fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1113 }
d2a409b2 1114 // Write a jdl with 2 input parameters: collection name and output dir name.
1115 WriteJDL(copy);
c57f56b7 1116 }
1117 // Copy jdl to grid workspace
a8739e8a 1118 if (copy) {
b5e4aaa7 1119 // Check if an output directory was defined and valid
1120 if (!fGridOutputDir.Length()) {
1121 Error("CreateJDL", "You must define AliEn output directory");
1122 return kFALSE;
1123 } else {
1124 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
bb2e67a0 1125 if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
b93f8109 1126 if (gGrid->Mkdir(fGridOutputDir,"-p")) {
b5e4aaa7 1127 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
1128 } else {
1129 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1130 return kFALSE;
1131 }
1132 }
1133 gGrid->Cd(workdir);
1134 }
648174cf 1135 if (TestBit(AliAnalysisGrid::kSubmit)) {
0f389141 1136 TString mergeJDLName = fExecutable;
1137 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
648174cf 1138 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
0f389141 1139 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1140 if (fProductionMode) {
648174cf 1141 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
0f389141 1142 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1143 }
648174cf 1144 if (FileExists(locjdl)) gGrid->Rm(locjdl);
0f389141 1145 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1146 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
648174cf 1147 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
0f389141 1148 if (fMergeViaJDL) {
1149 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1150 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1151 }
648174cf 1152 }
c57f56b7 1153 if (fAdditionalLibs.Length()) {
e7c71df0 1154 arr = fAdditionalLibs.Tokenize(" ");
c57f56b7 1155 TObjString *os;
1156 TIter next(arr);
1157 while ((os=(TObjString*)next())) {
c57f56b7 1158 if (os->GetString().Contains(".so")) continue;
4e5c5506 1159 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
c57f56b7 1160 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1161 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1162 }
1163 delete arr;
1164 }
4e5c5506 1165 if (fPackages) {
1166 TIter next(fPackages);
1167 TObject *obj;
1168 while ((obj=next())) {
fdbbc7be 1169 if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
4e5c5506 1170 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
1171 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1172 }
1173 }
c57f56b7 1174 }
1175 return kTRUE;
1176}
1177
a8739e8a 1178//______________________________________________________________________________
d2a409b2 1179Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
a8739e8a 1180{
1181// Writes one or more JDL's corresponding to findex. If findex is negative,
1182// all run numbers are considered in one go (jdl). For non-negative indices
1183// they correspond to the indices in the array fInputFiles.
1184 if (!fInputFiles) return kFALSE;
1185 TObjString *os;
a8739e8a 1186 TString workdir = gGrid->GetHomeDirectory();
1187 workdir += fGridWorkingDir;
d2a409b2 1188
1189 if (!fRunNumbers.Length() && !fRunRange[0]) {
1190 // One jdl with no parameters in case input data is specified by name.
a8739e8a 1191 TIter next(fInputFiles);
1192 while ((os=(TObjString*)next()))
0f389141 1193 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()), "Input xml collections");
648174cf 1194 if (!fOutputSingle.IsNull())
0f389141 1195 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1196 else {
1197 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1198 fMergingJDL->SetOutputDirectory(fGridOutputDir);
1199 }
a8739e8a 1200 } else {
d2a409b2 1201 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
0f389141 1202 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
cd11251e 1203 if (!fOutputSingle.IsNull()) {
0f389141 1204 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1205 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
cd11251e 1206 } else {
0f389141 1207 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
0cdf65a8 1208 fMergingJDL->SetOutputDirectory(Form("$1", fGridOutputDir.Data()), "Output directory");
cd11251e 1209 }
a8739e8a 1210 }
1211
1212
1213 // Generate the JDL as a string
1214 TString sjdl = fGridJDL->Generate();
0f389141 1215 TString sjdl1 = fMergingJDL->Generate();
a8739e8a 1216 Int_t index;
a8739e8a 1217 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1218 sjdl.ReplaceAll("(member", "\n (member");
1219 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1220 sjdl.ReplaceAll("{", "{\n ");
1221 sjdl.ReplaceAll("};", "\n};");
1222 sjdl.ReplaceAll("{\n \n", "{\n");
1223 sjdl.ReplaceAll("\n\n", "\n");
1224 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
0f389141 1225 sjdl1.ReplaceAll("\"LF:", "\n \"LF:");
1226 sjdl1.ReplaceAll("(member", "\n (member");
1227 sjdl1.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1228 sjdl1.ReplaceAll("{", "{\n ");
1229 sjdl1.ReplaceAll("};", "\n};");
1230 sjdl1.ReplaceAll("{\n \n", "{\n");
1231 sjdl1.ReplaceAll("\n\n", "\n");
1232 sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
a8739e8a 1233 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
f60ef0ba 1234 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
a8739e8a 1235 index = sjdl.Index("JDLVariables");
1236 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
4739b2aa 1237 sjdl += "Workdirectorysize = {\"5000MB\"};";
0f389141 1238 sjdl1 += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
7c2cd90a 1239 sjdl1.Prepend(Form("Jobtag = {\n \"comment:%s_Merging\"\n};\n", fJobTag.Data()));
1240 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 1241 index = sjdl1.Index("JDLVariables");
1242 if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
4739b2aa 1243 sjdl1 += "Workdirectorysize = {\"5000MB\"};";
a8739e8a 1244 // Write jdl to file
a8739e8a 1245 ofstream out;
d2a409b2 1246 out.open(fJDLName.Data(), ios::out);
a8739e8a 1247 if (out.bad()) {
d2a409b2 1248 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
a8739e8a 1249 return kFALSE;
1250 }
1251 out << sjdl << endl;
0f389141 1252 TString mergeJDLName = fExecutable;
1253 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1254 if (fMergeViaJDL) {
1255 ofstream out1;
1256 out1.open(mergeJDLName.Data(), ios::out);
1257 if (out.bad()) {
1258 Error("CreateJDL", "Bad file name: %s", mergeJDLName.Data());
1259 return kFALSE;
1260 }
1261 out1 << sjdl1 << endl;
1262 }
a8739e8a 1263
1264 // Copy jdl to grid workspace
1265 if (!copy) {
1266 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1267 } else {
d2a409b2 1268 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
0f389141 1269 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1270 if (fProductionMode) {
b5fe9cba 1271 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
0f389141 1272 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1273 }
d2a409b2 1274 if (FileExists(locjdl)) gGrid->Rm(locjdl);
0f389141 1275 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1276 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
5513444a 1277 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
0f389141 1278 if (fMergeViaJDL) {
1279 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1280 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1281 }
a8739e8a 1282 }
1283 return kTRUE;
1284}
1285
c57f56b7 1286//______________________________________________________________________________
5513444a 1287Bool_t AliAnalysisAlien::FileExists(const char *lfn)
c57f56b7 1288{
1289// Returns true if file exists.
5513444a 1290 if (!gGrid) return kFALSE;
c57f56b7 1291 TGridResult *res = gGrid->Ls(lfn);
1292 if (!res) return kFALSE;
1293 TMap *map = dynamic_cast<TMap*>(res->At(0));
1294 if (!map) {
1295 delete res;
1296 return kFALSE;
1297 }
1298 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1299 if (!objs || !objs->GetString().Length()) {
1300 delete res;
1301 return kFALSE;
1302 }
1303 delete res;
1304 return kTRUE;
1305}
1306
923e2ca5 1307//______________________________________________________________________________
1308Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1309{
1310// Returns true if directory exists. Can be also a path.
1311 if (!gGrid) return kFALSE;
1312 // Check if dirname is a path
1313 TString dirstripped = dirname;
1314 dirstripped = dirstripped.Strip();
1315 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1316 TString dir = gSystem->BaseName(dirstripped);
1317 dir += "/";
1318 TString path = gSystem->DirName(dirstripped);
1319 TGridResult *res = gGrid->Ls(path, "-F");
1320 if (!res) return kFALSE;
1321 TIter next(res);
1322 TMap *map;
1323 TObject *obj;
1324 while ((map=dynamic_cast<TMap*>(next()))) {
1325 obj = map->GetValue("name");
1326 if (!obj) break;
1327 if (dir == obj->GetName()) {
1328 delete res;
1329 return kTRUE;
1330 }
1331 }
1332 delete res;
1333 return kFALSE;
1334}
1335
c57f56b7 1336//______________________________________________________________________________
a2f5fc01 1337void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
c57f56b7 1338{
1339// Check input data type.
a2f5fc01 1340 isCollection = kFALSE;
1341 isXml = kFALSE;
1342 useTags = kFALSE;
c57f56b7 1343 if (!gGrid) {
1344 Error("CheckDataType", "No connection to grid");
1345 return;
1346 }
a2f5fc01 1347 isCollection = IsCollection(lfn);
c57f56b7 1348 TString msg = "\n##### file: ";
1349 msg += lfn;
a2f5fc01 1350 if (isCollection) {
c57f56b7 1351 msg += " type: raw_collection;";
1352 // special treatment for collections
a2f5fc01 1353 isXml = kFALSE;
c57f56b7 1354 // check for tag files in the collection
1355 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1356 if (!res) {
1357 msg += " using_tags: No (unknown)";
1358 Info("CheckDataType", msg.Data());
1359 return;
1360 }
1361 const char* typeStr = res->GetKey(0, "origLFN");
1362 if (!typeStr || !strlen(typeStr)) {
1363 msg += " using_tags: No (unknown)";
1364 Info("CheckDataType", msg.Data());
1365 return;
1366 }
1367 TString file = typeStr;
a2f5fc01 1368 useTags = file.Contains(".tag");
1369 if (useTags) msg += " using_tags: Yes";
c57f56b7 1370 else msg += " using_tags: No";
1371 Info("CheckDataType", msg.Data());
1372 return;
1373 }
1374 TString slfn(lfn);
1375 slfn.ToLower();
a2f5fc01 1376 isXml = slfn.Contains(".xml");
1377 if (isXml) {
c57f56b7 1378 // Open xml collection and check if there are tag files inside
1379 msg += " type: xml_collection;";
1380 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1381 if (!coll) {
1382 msg += " using_tags: No (unknown)";
1383 Info("CheckDataType", msg.Data());
1384 return;
1385 }
1386 TMap *map = coll->Next();
1387 if (!map) {
1388 msg += " using_tags: No (unknown)";
1389 Info("CheckDataType", msg.Data());
1390 return;
1391 }
1392 map = (TMap*)map->GetValue("");
1393 TString file;
1394 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
a2f5fc01 1395 useTags = file.Contains(".tag");
c57f56b7 1396 delete coll;
a2f5fc01 1397 if (useTags) msg += " using_tags: Yes";
c57f56b7 1398 else msg += " using_tags: No";
1399 Info("CheckDataType", msg.Data());
1400 return;
1401 }
a2f5fc01 1402 useTags = slfn.Contains(".tag");
c57f56b7 1403 if (slfn.Contains(".root")) msg += " type: root file;";
f866cba5 1404 else msg += " type: unknown file;";
a2f5fc01 1405 if (useTags) msg += " using_tags: Yes";
c57f56b7 1406 else msg += " using_tags: No";
1407 Info("CheckDataType", msg.Data());
1408}
1409
4e5c5506 1410//______________________________________________________________________________
1411void AliAnalysisAlien::EnablePackage(const char *package)
1412{
1413// Enables a par file supposed to exist in the current directory.
1414 TString pkg(package);
1415 pkg.ReplaceAll(".par", "");
1416 pkg += ".par";
1417 if (gSystem->AccessPathName(pkg)) {
ebcdf05e 1418 Fatal("EnablePackage", "Package %s not found", pkg.Data());
4e5c5506 1419 return;
1420 }
1421 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1422 Info("EnablePackage", "AliEn plugin will use .par packages");
1423 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1424 if (!fPackages) {
1425 fPackages = new TObjArray();
1426 fPackages->SetOwner();
1427 }
1428 fPackages->Add(new TObjString(pkg));
1429}
1430
d2a409b2 1431//______________________________________________________________________________
1432const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1433{
1434// Get job status for all jobs with jobid>jobidstart.
1435 static char mstatus[20];
1436 mstatus[0] = '\0';
1437 nrunning = 0;
1438 nwaiting = 0;
1439 nerror = 0;
1440 ndone = 0;
1441 TGridJobStatusList *list = gGrid->Ps("");
1442 if (!list) return mstatus;
1443 Int_t nentries = list->GetSize();
1444 TGridJobStatus *status;
1445 Int_t pid;
1446 for (Int_t ijob=0; ijob<nentries; ijob++) {
1447 status = (TGridJobStatus *)list->At(ijob);
1448 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1449 if (pid<jobidstart) continue;
1450 if (pid == lastid) {
1451 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1452 }
1453 switch (status->GetStatus()) {
1454 case TGridJobStatus::kWAITING:
1455 nwaiting++; break;
1456 case TGridJobStatus::kRUNNING:
1457 nrunning++; break;
1458 case TGridJobStatus::kABORTED:
1459 case TGridJobStatus::kFAIL:
1460 case TGridJobStatus::kUNKNOWN:
1461 nerror++; break;
1462 case TGridJobStatus::kDONE:
1463 ndone++;
1464 }
1465 }
1466 list->Delete();
1467 delete list;
1468 return mstatus;
1469}
1470
c57f56b7 1471//______________________________________________________________________________
1472Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1473{
1474// Returns true if file is a collection. Functionality duplicated from
1475// TAlien::Type() because we don't want to directly depend on TAlien.
1476 if (!gGrid) {
1477 Error("IsCollection", "No connection to grid");
1478 return kFALSE;
1479 }
1480 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1481 if (!res) return kFALSE;
1482 const char* typeStr = res->GetKey(0, "type");
1483 if (!typeStr || !strlen(typeStr)) return kFALSE;
1484 if (!strcmp(typeStr, "collection")) return kTRUE;
1485 delete res;
1486 return kFALSE;
1487}
1488
fe2d7fc2 1489//______________________________________________________________________________
1490Bool_t AliAnalysisAlien::IsSingleOutput() const
1491{
1492// Check if single-ouput option is on.
1493 return (!fOutputSingle.IsNull());
1494}
1495
16a4353c 1496//______________________________________________________________________________
1497void AliAnalysisAlien::Print(Option_t *) const
1498{
1499// Print current plugin settings.
84fcd93f 1500 printf("### AliEn analysis plugin current settings ###\n");
e1c22e21 1501 printf("= OverwriteMode:________________________________ %d\n", fOverwriteMode);
1502 if (fOverwriteMode) {
1503 printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
1504 \n***** To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
1505 }
348be253 1506 printf("= Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
1507 printf("= Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
84fcd93f 1508 printf("= Production mode:______________________________ %d\n", fProductionMode);
1509 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1510 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1511 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
16a4353c 1512 if (fUser.Length())
84fcd93f 1513 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1514 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1515 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1516 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1517 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1518 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
16a4353c 1519 if (fRunNumbers.Length())
84fcd93f 1520 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
16a4353c 1521 if (fRunRange[0])
5fce53f4 1522 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
16a4353c 1523 if (!fRunRange[0] && !fRunNumbers.Length()) {
1524 TIter next(fInputFiles);
1525 TObject *obj;
1526 TString list;
1527 while ((obj=next())) list += obj->GetName();
84fcd93f 1528 printf("= Input files to be processed: _________________ %s\n", list.Data());
16a4353c 1529 }
1530 if (TestBit(AliAnalysisGrid::kTest))
84fcd93f 1531 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1532 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1533 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1534 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1535 printf("=====================================================================\n");
1536 printf("= Job price: ___________________________________ %d\n", fPrice);
1537 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1538 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
16a4353c 1539 if (fMaxInitFailed>0)
84fcd93f 1540 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
16a4353c 1541 if (fMasterResubmitThreshold>0)
84fcd93f 1542 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
149d288c 1543 printf("= Number of replicas for the output files_______ %d\n", fNreplicas);
319593fb 1544 if (fNrunsPerMaster>0)
84fcd93f 1545 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1546 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
b5b9dee8 1547 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1548 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
16a4353c 1549 if (fArguments.Length())
84fcd93f 1550 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
631c0b05 1551 if (fExecutableArgs.Length())
1552 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
84fcd93f 1553 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1554 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1555 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1556 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
16a4353c 1557 if (fDatasetName)
84fcd93f 1558 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1559 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
16a4353c 1560 if (fIncludePath.Data())
84fcd93f 1561 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
16a4353c 1562 if (fCloseSE.Length())
84fcd93f 1563 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
16a4353c 1564 if (fFriendChainName.Length())
84fcd93f 1565 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
16a4353c 1566 if (fPackages) {
1567 TIter next(fPackages);
1568 TObject *obj;
1569 TString list;
1570 while ((obj=next())) list += obj->GetName();
84fcd93f 1571 printf("= Par files to be used: ________________________ %s\n", list.Data());
16a4353c 1572 }
1573}
1574
c57f56b7 1575//______________________________________________________________________________
1576void AliAnalysisAlien::SetDefaults()
1577{
1578// Set default values for everything. What cannot be filled will be left empty.
1579 if (fGridJDL) delete fGridJDL;
1580 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
0f389141 1581 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
c57f56b7 1582 fPrice = 1;
1583 fTTL = 30000;
1584 fSplitMaxInputFileNumber = 100;
1585 fMaxInitFailed = 0;
1586 fMasterResubmitThreshold = 0;
bb885a9e 1587 fNtestFiles = 10;
149d288c 1588 fNreplicas = 2;
a8739e8a 1589 fRunRange[0] = 0;
1590 fRunRange[1] = 0;
319593fb 1591 fNrunsPerMaster = 1;
16a4353c 1592 fMaxMergeFiles = 100;
c57f56b7 1593 fRunNumbers = "";
1594 fExecutable = "analysis.sh";
0a1c1f7f 1595 fExecutableCommand = "root -b -q";
c57f56b7 1596 fArguments = "";
631c0b05 1597 fExecutableArgs = "";
c57f56b7 1598 fAnalysisMacro = "myAnalysis.C";
1599 fAnalysisSource = "";
1600 fAdditionalLibs = "";
1601 fSplitMode = "se";
1602 fAPIVersion = "";
1603 fROOTVersion = "";
1604 fAliROOTVersion = "";
1605 fUser = ""; // Your alien user name
1606 fGridWorkingDir = "";
1607 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1608 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
0df6ccf2 1609 fFriendChainName = "";
c57f56b7 1610 fGridOutputDir = "output";
149d288c 1611 fOutputArchive = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
c57f56b7 1612 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1613 fInputFormat = "xml-single";
1614 fJDLName = "analysis.jdl";
c6cb3634 1615 fJobTag = "Automatically generated analysis JDL";
bb885a9e 1616 fMergeExcludes = "";
0f389141 1617 fMergeViaJDL = 0;
348be253 1618 SetUseCopy(kTRUE);
1619 SetCheckCopy(kTRUE);
149d288c 1620 SetDefaultOutputs(kTRUE);
e1c22e21 1621 fOverwriteMode = 1;
c57f56b7 1622}
1623
0f389141 1624//______________________________________________________________________________
7c2cd90a 1625Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, Bool_t submit, const char *jdl)
0f389141 1626{
7c2cd90a 1627// Static method that checks the status of merging. This can submit merging jobs that did not produced the expected
1628// output. If <submit> is false (checking) returns true only when the final merged file was found. If submit is true returns
1629// true if the jobs were successfully submitted.
1630 Int_t countOrig = 0;
1631 Int_t countStage = 0;
1632 Int_t stage = 0;
1633 Int_t i;
1634 Bool_t doneFinal = kFALSE;
1635 TBits chunksDone;
1636 TString saliendir(aliendir);
1637 TString sfilename, stmp;
1638 saliendir.ReplaceAll("//","/");
1639 saliendir = saliendir.Strip(TString::kTrailing, '/');
1640 if (!gGrid) {
1641 ::Error("GetNregisteredFiles", "You need to be connected to AliEn.");
1642 return kFALSE;
1643 }
0cdf65a8 1644 sfilename = filename;
1645 sfilename.ReplaceAll(".root", "*.root");
1646 printf("Checking directory <%s> for merged files <%s> ...\n", aliendir, sfilename.Data());
1647 TString command = Form("find %s/ *%s", saliendir.Data(), sfilename.Data());
7c2cd90a 1648 TGridResult *res = gGrid->Command(command);
1649 if (!res) {
1650 ::Error("GetNregisteredFiles","Error: No result for the find command\n");
1651 return kFALSE;
1652 }
1653 TIter nextmap(res);
1654 TMap *map = 0;
1655 while ((map=(TMap*)nextmap())) {
1656 TString turl = map->GetValue("turl")->GetName();
1657 if (!turl.Length()) {
1658 // Nothing found
1659 delete res;
1660 return kFALSE;
1661 }
1662 turl.ReplaceAll("alien://", "");
1663 turl.ReplaceAll(saliendir, "");
1664 sfilename = gSystem->BaseName(turl);
0cdf65a8 1665 turl = turl.Strip(TString::kLeading, '/');
7c2cd90a 1666 // Now check to what the file corresponds to:
1667 // original output - aliendir/%03d/filename
1668 // merged file (which stage) - aliendir/filename-Stage%02d_%04d
1669 // final merged file - aliendir/filename
1670 if (sfilename == turl) {
1671 if (sfilename == filename) {
1672 doneFinal = kTRUE;
1673 } else {
1674 // check stage
1675 Int_t index = sfilename.Index("Stage");
1676 if (index<0) continue;
1677 stmp = sfilename(index+5,2);
1678 Int_t istage = atoi(stmp);
1679 stmp = sfilename(index+8,4);
1680 Int_t ijob = atoi(stmp);
1681 if (istage<stage) continue; // Ignore lower stages
1682 if (istage>stage) {
1683 countStage = 0;
1684 chunksDone.ResetAllBits();
1685 stage = istage;
1686 }
1687 countStage++;
1688 chunksDone.SetBitNumber(ijob);
1689 }
1690 } else {
1691 countOrig++;
1692 }
1693 if (doneFinal) {
1694 delete res;
0cdf65a8 1695 printf("=> Removing files from previous stages...\n");
1696 gGrid->Rm(Form("%s/*Stage*.root", aliendir));
7c2cd90a 1697 return kTRUE;
1698 }
1699 }
1700 delete res;
1701 // Compute number of jobs that were submitted for the current stage
1702 Int_t ntotstage = countOrig;
7ae54d70 1703 for (i=1; i<=stage; i++) {
1704 if (ntotstage%nperchunk) ntotstage = (ntotstage/nperchunk)+1;
1705 else ntotstage = (ntotstage/nperchunk);
1706 }
7c2cd90a 1707 // Now compare with the number of set bits in the chunksDone array
1708 Int_t nmissing = (stage>0)?(ntotstage - countStage):0;
1709 // Print the info
1710 printf("*** Found %d original files\n", countOrig);
1711 if (stage==0) printf("*** No merging completed so far.\n");
1712 else printf("*** Found %d out of %d files merged for stage %d\n", countStage, ntotstage, stage);
1713 if (nmissing) printf("*** Number of merged files missing for this stage: %d -> check merging job completion\n", nmissing);
7c2cd90a 1714 if (!submit) return doneFinal;
1715 // Sumbit merging jobs for all missing chunks for the current stage.
1716 TString query = Form("submit %s %s", jdl, aliendir);
1717 Int_t ichunk = -1;
1718 if (nmissing) {
1719 for (i=0; i<nmissing; i++) {
1720 ichunk = chunksDone.FirstNullBit(ichunk+1);
1721 Int_t jobId = SubmitSingleJob(Form("%s %d %d", query.Data(), stage, ichunk));
1722 if (!jobId) return kFALSE;
1723 }
1724 return kTRUE;
1725 }
1726 // Submit next stage of merging
1727 if (stage==0) countStage = countOrig;
7ae54d70 1728 Int_t nchunks = (countStage/nperchunk);
1729 if (countStage%nperchunk) nchunks += 1;
7c2cd90a 1730 for (i=0; i<nchunks; i++) {
1731 Int_t jobId = SubmitSingleJob(Form("%s %d %d", query.Data(), stage+1, i));
1732 if (!jobId) return kFALSE;
1733 }
1734 return kTRUE;
1735}
1736
1737//______________________________________________________________________________
1738Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
1739{
1740// Submits a single job corresponding to the query and returns job id. If 0 submission failed.
1741 if (!gGrid) return 0;
1742 printf("=> %s ------> ",query);
1743 TGridResult *res = gGrid->Command(query);
1744 if (!res) return 0;
1745 TString jobId = res->GetKey(0,"jobId");
1746 delete res;
1747 if (jobId.IsNull()) {
1748 printf("submission failed. Reason:\n");
1749 gGrid->Stdout();
1750 gGrid->Stderr();
1751 ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
1752 return 0;
1753 }
1754 printf(" Job id: %s\n", jobId.Data());
1755 return atoi(jobId);
1756}
1757
1758//______________________________________________________________________________
1759Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage, Int_t ichunk)
1760{
1761// Merge given output files from basedir. The file merger will merge nmaxmerge
1762// files in a group. Merging can be done in stages:
1763// stage=0 : will merge all existing files in a single stage
1764// stage=1 : does a find command for all files that do NOT contain the string "Stage".
1765// If their number is bigger that nmaxmerge, only the files from
1766// ichunk*nmaxmerge to ichunk*(nmaxmerge+1)-1 will get merged as output_stage_<ichunk>
1767// stage=n : does a find command for files named <output>Stage<stage-1>_*. If their number is bigger than
1768// nmaxmerge, merge just the chunk ichunk, otherwise write the merged output to the file
1769// named <output>.
a2f5fc01 1770 TString outputFile = output;
0f389141 1771 TString command;
a2f5fc01 1772 TString outputChunk;
1773 TString previousChunk = "";
1774 Int_t countChunk = 0;
1775 Int_t countZero = nmaxmerge;
0f389141 1776 Bool_t merged = kTRUE;
a2f5fc01 1777 Int_t index = outputFile.Index("@");
1778 if (index > 0) outputFile.Remove(index);
7c2cd90a 1779 TString inputFile = outputFile;
1780 if (stage>1) inputFile.ReplaceAll(".root", Form("-Stage%02d_*.root", stage-1));
1781 command = Form("find %s/ *%s", basedir, inputFile.Data());
0f389141 1782 printf("command: %s\n", command.Data());
1783 TGridResult *res = gGrid->Command(command);
1784 if (!res) {
7c2cd90a 1785 ::Error("MergeOutput","No result for the find command\n");
0f389141 1786 return kFALSE;
1787 }
1788
1789 TFileMerger *fm = 0;
1790 TIter nextmap(res);
1791 TMap *map = 0;
7c2cd90a 1792 // Check if there is a merge operation to resume. Works only for stage 0 or 1.
a2f5fc01 1793 outputChunk = outputFile;
1794 outputChunk.ReplaceAll(".root", "_*.root");
0f389141 1795 // Check for existent temporary merge files
e1c22e21 1796 // Check overwrite mode and remove previous partial results if needed
7c2cd90a 1797 // Preserve old merging functionality for stage 0.
1798 if (stage==0) {
1799 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
1800 while (1) {
1801 // Skip as many input files as in a chunk
1802 for (Int_t counter=0; counter<nmaxmerge; counter++) map = (TMap*)nextmap();
1803 if (!map) {
1804 ::Error("MergeOutput", "Cannot resume merging for <%s>, nentries=%d", outputFile.Data(), res->GetSize());
1805 delete res;
1806 return kFALSE;
1807 }
1808 outputChunk = outputFile;
1809 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
1810 countChunk++;
1811 if (gSystem->AccessPathName(outputChunk)) continue;
1812 // Merged file with chunks up to <countChunk> found
1813 ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
1814 previousChunk = outputChunk;
1815 break;
1816 }
1817 }
1818 countZero = nmaxmerge;
1819
1820 while ((map=(TMap*)nextmap())) {
1821 // Loop 'find' results and get next LFN
1822 if (countZero == nmaxmerge) {
1823 // First file in chunk - create file merger and add previous chunk if any.
1824 fm = new TFileMerger(kFALSE);
1825 fm->SetFastMethod(kTRUE);
1826 if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
1827 outputChunk = outputFile;
1828 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
1829 }
1830 // If last file found, put merged results in the output file
1831 if (map == res->Last()) outputChunk = outputFile;
1832 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1833 if (!objs || !objs->GetString().Length()) {
1834 // Nothing found - skip this output
0f389141 1835 delete res;
7c2cd90a 1836 delete fm;
0f389141 1837 return kFALSE;
7c2cd90a 1838 }
1839 // Add file to be merged and decrement chunk counter.
1840 fm->AddFile(objs->GetString());
1841 countZero--;
1842 if (countZero==0 || map == res->Last()) {
1843 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1844 // Nothing found - skip this output
1845 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
1846 delete res;
1847 delete fm;
1848 return kFALSE;
1849 }
1850 fm->OutputFile(outputChunk);
1851 // Merge the outputs, then go to next chunk
1852 if (!fm->Merge()) {
1853 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
1854 delete res;
1855 delete fm;
1856 return kFALSE;
1857 } else {
1858 ::Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
1859 gSystem->Unlink(previousChunk);
1860 }
1861 if (map == res->Last()) {
1862 delete res;
1863 delete fm;
1864 break;
1865 }
1866 countChunk++;
1867 countZero = nmaxmerge;
1868 previousChunk = outputChunk;
0f389141 1869 }
0f389141 1870 }
7c2cd90a 1871 return merged;
1872 }
1873 // Merging stage different than 0.
1874 // Move to the begining of the requested chunk.
1875 outputChunk = outputFile;
1876 if (nmaxmerge < res->GetSize()) {
1877 if (ichunk*nmaxmerge >= res->GetSize()) {
1878 ::Error("MergeOutput", "Cannot merge merge chunk %d grouping %d files from %d total.", ichunk, nmaxmerge, res->GetSize());
1879 delete res;
1880 return kFALSE;
1881 }
1882 for (Int_t counter=0; counter<ichunk*nmaxmerge; counter++) map = (TMap*)nextmap();
1883 outputChunk.ReplaceAll(".root", Form("-Stage%02d_%04d.root", stage, ichunk));
1884 }
1885 countZero = nmaxmerge;
1886 fm = new TFileMerger(kFALSE);
1887 fm->SetFastMethod(kTRUE);
0f389141 1888 while ((map=(TMap*)nextmap())) {
7c2cd90a 1889 // Loop 'find' results and get next LFN
0f389141 1890 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1891 if (!objs || !objs->GetString().Length()) {
1892 // Nothing found - skip this output
1893 delete res;
1894 delete fm;
1895 return kFALSE;
1896 }
1897 // Add file to be merged and decrement chunk counter.
1898 fm->AddFile(objs->GetString());
a2f5fc01 1899 countZero--;
7c2cd90a 1900 if (countZero==0) break;
1901 }
1902 delete res;
1903 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1904 // Nothing found - skip this output
1905 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
1906 delete fm;
1907 return kFALSE;
1908 }
1909 fm->OutputFile(outputChunk);
1910 // Merge the outputs
1911 if (!fm->Merge()) {
1912 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
1913 delete fm;
1914 return kFALSE;
1915 } else {
1916 ::Info("MergeOutput", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
0f389141 1917 }
7c2cd90a 1918 delete fm;
1919 return kTRUE;
0f389141 1920}
1921
c57f56b7 1922//______________________________________________________________________________
1923Bool_t AliAnalysisAlien::MergeOutputs()
1924{
1925// Merge analysis outputs existing in the AliEn space.
1926 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1927 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1928 if (!Connect()) {
1929 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1930 return kFALSE;
0f389141 1931 }
c9e8f7fd 1932 if (fMergeViaJDL) {
1933 if (!TestBit(AliAnalysisGrid::kMerge)) {
1934 Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
1935 return kFALSE;
1936 }
1937 if (fProductionMode) {
1938 Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
1939 return kFALSE;
1940 }
0f389141 1941 Info("MergeOutputs", "Submitting merging JDL");
a03be957 1942 if (!SubmitMerging()) return kFALSE;
0f389141 1943 Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
c9e8f7fd 1944 Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
001cb79e 1945 return kFALSE;
c57f56b7 1946 }
1947 // Get the output path
d2a409b2 1948 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
923e2ca5 1949 if (!DirectoryExists(fGridOutputDir)) {
c57f56b7 1950 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1951 return kFALSE;
1952 }
1953 if (!fOutputFiles.Length()) {
1954 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1955 return kFALSE;
0f389141 1956 }
1957 // Check if fast read option was requested
e1c22e21 1958 Info("MergeOutputs", "Started local merging of output files from: alien://%s \
1959 \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
0f389141 1960 if (fFastReadOption) {
d3339be3 1961 Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
1962 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
1963 gEnv->SetValue("XNet.ConnectTimeout",10);
1964 gEnv->SetValue("XNet.RequestTimeout",10);
0f389141 1965 gEnv->SetValue("XNet.MaxRedirectCount",2);
d3339be3 1966 gEnv->SetValue("XNet.ReconnectTimeout",10);
0f389141 1967 gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
c57f56b7 1968 }
e8b839ab 1969 // Make sure we change the temporary directory
1970 gSystem->Setenv("TMPDIR", gSystem->pwd());
149d288c 1971 TObjArray *list = fOutputFiles.Tokenize(",");
c57f56b7 1972 TIter next(list);
1973 TObjString *str;
a2f5fc01 1974 TString outputFile;
c57f56b7 1975 Bool_t merged = kTRUE;
1976 while((str=(TObjString*)next())) {
a2f5fc01 1977 outputFile = str->GetString();
1978 Int_t index = outputFile.Index("@");
1979 if (index > 0) outputFile.Remove(index);
1980 TString outputChunk = outputFile;
1981 outputChunk.ReplaceAll(".root", "_*.root");
319593fb 1982 // Skip already merged outputs
a2f5fc01 1983 if (!gSystem->AccessPathName(outputFile)) {
e1c22e21 1984 if (fOverwriteMode) {
a2f5fc01 1985 Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
1986 gSystem->Unlink(outputFile);
1987 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
e1c22e21 1988 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
a2f5fc01 1989 outputChunk.Data());
1990 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
e1c22e21 1991 }
1992 } else {
a2f5fc01 1993 Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
e1c22e21 1994 continue;
1995 }
1996 } else {
a2f5fc01 1997 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
e1c22e21 1998 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
a2f5fc01 1999 outputChunk.Data());
2000 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
e1c22e21 2001 }
2002 }
bb885a9e 2003 if (fMergeExcludes.Length() &&
a2f5fc01 2004 fMergeExcludes.Contains(outputFile.Data())) continue;
16a4353c 2005 // Perform a 'find' command in the output directory, looking for registered outputs
a2f5fc01 2006 merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
0f389141 2007 if (!merged) {
2008 Error("MergeOutputs", "Terminate() will NOT be executed");
2009 return kFALSE;
ff07ec61 2010 }
2011 TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2012 if (fileOpened) fileOpened->Close();
c57f56b7 2013 }
0f389141 2014 return kTRUE;
c57f56b7 2015}
2016
bb885a9e 2017//______________________________________________________________________________
2018void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2019{
2020// Use the output files connected to output containers from the analysis manager
2021// rather than the files defined by SetOutputFiles
2022 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
205b201f 2023 Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
bb885a9e 2024 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2025}
2026
149d288c 2027//______________________________________________________________________________
2028void AliAnalysisAlien::SetOutputFiles(const char *list)
2029{
2030// Manually set the output files list.
2031// Removes duplicates. Not allowed if default outputs are not disabled.
2032 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2033 Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2034 return;
2035 }
2036 Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2037 fOutputFiles = "";
2038 TString slist = list;
2039 if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2040 TObjArray *arr = slist.Tokenize(" ");
2041 TObjString *os;
2042 TIter next(arr);
2043 TString sout;
2044 while ((os=(TObjString*)next())) {
2045 sout = os->GetString();
2046 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2047 if (fOutputFiles.Contains(sout)) continue;
2048 if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2049 fOutputFiles += sout;
2050 }
2051 delete arr;
2052}
2053
2054//______________________________________________________________________________
2055void AliAnalysisAlien::SetOutputArchive(const char *list)
2056{
2057// Manually set the output archive list. Free text - you are on your own...
2058// Not allowed if default outputs are not disabled.
2059 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2060 Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2061 return;
2062 }
2063 Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2064 fOutputArchive = list;
2065}
2066
2067//______________________________________________________________________________
2068void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2069{
2070// Setting a prefered output SE is not allowed anymore.
2071 Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2072}
2073
5513444a 2074//______________________________________________________________________________
2075Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
c57f56b7 2076{
2077// Start remote grid analysis.
2078
43da816a 2079 // Check if output files have to be taken from the analysis manager
2080 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2081 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2082 if (!mgr || !mgr->IsInitialized()) {
2083 Error("StartAnalysis", "You need an initialized analysis manager for this");
5513444a 2084 return kFALSE;
43da816a 2085 }
2086 fOutputFiles = "";
2087 TIter next(mgr->GetOutputs());
2088 AliAnalysisDataContainer *output;
2089 while ((output=(AliAnalysisDataContainer*)next())) {
2090 const char *filename = output->GetFileName();
2091 if (!(strcmp(filename, "default"))) {
2092 if (!mgr->GetOutputEventHandler()) continue;
2093 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
2094 }
84fcd93f 2095 if (fOutputFiles.Contains(filename)) continue;
149d288c 2096 if (fOutputFiles.Length()) fOutputFiles += ",";
43da816a 2097 fOutputFiles += filename;
2098 }
c07b9ce2 2099 // Add extra files registered to the analysis manager
2100 if (mgr->GetExtraFiles().Length()) {
149d288c 2101 if (fOutputFiles.Length()) fOutputFiles += ",";
2102 TString extra = mgr->GetExtraFiles();
2103 extra.ReplaceAll(" ", ",");
2104 // Protection in case extra files do not exist (will it work?)
2105 extra.ReplaceAll(".root", "*.root");
2106 fOutputFiles += extra;
84fcd93f 2107 }
149d288c 2108 // Compose the output archive.
2109 fOutputArchive = "log_archive.zip:std*@disk=1 ";
2110 fOutputArchive += Form("root_archive.zip:%s@disk=%d",fOutputFiles.Data(),fNreplicas);
43da816a 2111 }
f7b1cbc2 2112// if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
c57f56b7 2113 if (TestBit(AliAnalysisGrid::kOffline)) {
2114 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2115 \n there nor any job run. You can revise the JDL and analysis \
2116 \n macro then run the same in \"submit\" mode.");
2117 } else if (TestBit(AliAnalysisGrid::kTest)) {
2118 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
2119 \n dataset.");
2120 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2121 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
2122 \n space and job submitted.");
2123 } else if (TestBit(AliAnalysisGrid::kMerge)) {
2124 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
0f389141 2125 if (fMergeViaJDL) CheckInputData();
5513444a 2126 return kTRUE;
c57f56b7 2127 } else {
2128 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
2129 }
2130
348be253 2131 Print();
c57f56b7 2132 if (!Connect()) {
2133 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
5513444a 2134 return kFALSE;
16a4353c 2135 }
348be253 2136 if (IsCheckCopy()) CheckFileCopy(gGrid->GetHomeDirectory());
c57f56b7 2137 if (!CheckInputData()) {
2138 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
5513444a 2139 return kFALSE;
c57f56b7 2140 }
d3339be3 2141 if (!CreateDataset(fDataPattern)) {
2142 TString serror;
2143 if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2144 if (fRunNumbers.Length()) serror = "run numbers";
2145 if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2146 serror += Form("\n or data pattern <%s>", fDataPattern.Data());
2147 Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2148 return kFALSE;
2149 }
c57f56b7 2150 WriteAnalysisFile();
2151 WriteAnalysisMacro();
2152 WriteExecutable();
2153 WriteValidationScript();
0f389141 2154 if (fMergeViaJDL) {
2155 WriteMergingMacro();
2156 WriteMergeExecutable();
2157 WriteValidationScript(kTRUE);
2158 }
5513444a 2159 if (!CreateJDL()) return kFALSE;
2160 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
c57f56b7 2161 if (TestBit(AliAnalysisGrid::kTest)) {
2162 // Locally testing the analysis
2163 Info("StartAnalysis", "\n_______________________________________________________________________ \
2164 \n Running analysis script in a daughter shell as on a worker node \
2165 \n_______________________________________________________________________");
149d288c 2166 TObjArray *list = fOutputFiles.Tokenize(",");
c57f56b7 2167 TIter next(list);
2168 TObjString *str;
a2f5fc01 2169 TString outputFile;
c57f56b7 2170 while((str=(TObjString*)next())) {
a2f5fc01 2171 outputFile = str->GetString();
2172 Int_t index = outputFile.Index("@");
2173 if (index > 0) outputFile.Remove(index);
2174 if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
c57f56b7 2175 }
2176 delete list;
2177 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
0d5d317c 2178 TString validationScript = fExecutable;
2179 validationScript.ReplaceAll(".sh", "_validation.sh");
2180 gSystem->Exec(Form("bash %s",validationScript.Data()));
c57f56b7 2181// gSystem->Exec("cat stdout");
5513444a 2182 return kFALSE;
c57f56b7 2183 }
5513444a 2184 // Check if submitting is managed by LPM manager
a3e84053 2185 if (fProductionMode) {
5513444a 2186 TString prodfile = fJDLName;
2187 prodfile.ReplaceAll(".jdl", ".prod");
2188 WriteProductionFile(prodfile);
2189 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2190 return kFALSE;
2191 }
a8739e8a 2192 // Submit AliEn job(s)
d2a409b2 2193 gGrid->Cd(fGridOutputDir);
a8739e8a 2194 TGridResult *res;
c57f56b7 2195 TString jobID = "";
d2a409b2 2196 if (!fRunNumbers.Length() && !fRunRange[0]) {
dd74a515 2197 // Submit a given xml or a set of runs
a8739e8a 2198 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
84fcd93f 2199 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
a8739e8a 2200 if (res) {
2201 const char *cjobId = res->GetKey(0,"jobId");
2202 if (!cjobId) {
a03be957 2203 gGrid->Stdout();
2204 gGrid->Stderr();
a8739e8a 2205 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
5513444a 2206 return kFALSE;
a8739e8a 2207 } else {
2208 Info("StartAnalysis", "\n_______________________________________________________________________ \
2209 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2210 \n_______________________________________________________________________",
2211 fJDLName.Data(), cjobId);
2212 jobID = cjobId;
2213 }
2214 delete res;
a03be957 2215 } else {
2216 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2217 return kFALSE;
a8739e8a 2218 }
2219 } else {
d2a409b2 2220 // Submit for a range of enumeration of runs.
a03be957 2221 if (!Submit()) return kFALSE;
c57f56b7 2222 }
a8739e8a 2223
c57f56b7 2224 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2225 \n You may exit at any time and terminate the job later using the option <terminate> \
2226 \n ##################################################################################", jobID.Data());
bb885a9e 2227 gSystem->Exec("aliensh");
5513444a 2228 return kTRUE;
c57f56b7 2229}
2230
d2a409b2 2231//______________________________________________________________________________
a03be957 2232Bool_t AliAnalysisAlien::Submit()
d2a409b2 2233{
2234// Submit all master jobs.
2235 Int_t nmasterjobs = fInputFiles->GetEntries();
2236 Long_t tshoot = gSystem->Now();
a03be957 2237 if (!fNsubmitted && !SubmitNext()) return kFALSE;
d2a409b2 2238 while (fNsubmitted < nmasterjobs) {
2239 Long_t now = gSystem->Now();
2240 if ((now-tshoot)>30000) {
2241 tshoot = now;
a03be957 2242 if (!SubmitNext()) return kFALSE;
d2a409b2 2243 }
2244 }
a03be957 2245 return kTRUE;
d2a409b2 2246}
2247
0f389141 2248//______________________________________________________________________________
a03be957 2249Bool_t AliAnalysisAlien::SubmitMerging()
0f389141 2250{
2251// Submit all merging jobs.
2252 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2253 gGrid->Cd(fGridOutputDir);
2254 TString mergeJDLName = fExecutable;
2255 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2256 Int_t ntosubmit = fInputFiles->GetEntries();
0f389141 2257 for (Int_t i=0; i<ntosubmit; i++) {
f866cba5 2258 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2259 runOutDir.ReplaceAll(".xml", "");
7c2cd90a 2260 if (fOutputToRunNo) {
2261 // The output directory is the run number
2262 printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
2263 runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
2264 } else {
2265 // The output directory is the master number in 3 digits format
2266 printf("### Submitting merging job for master <%03d>\n", i);
2267 runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
2268 }
2269 // Check now the number of merging stages.
2b222f7c 2270 TObjArray *list = fOutputFiles.Tokenize(",");
2271 TIter next(list);
2272 TObjString *str;
2273 TString outputFile;
2274 while((str=(TObjString*)next())) {
2275 outputFile = str->GetString();
2276 Int_t index = outputFile.Index("@");
2277 if (index > 0) outputFile.Remove(index);
2278 if (!fMergeExcludes.Contains(outputFile)) break;
2279 }
2280 delete list;
7c2cd90a 2281 Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, kTRUE, mergeJDLName);
2282 if (!done) return kFALSE;
0f389141 2283 }
a03be957 2284 if (!ntosubmit) return kTRUE;
0f389141 2285 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
2286 \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
2287 \n ##################################################################################");
2288 gSystem->Exec("aliensh");
a03be957 2289 return kTRUE;
0f389141 2290}
2291
d2a409b2 2292//______________________________________________________________________________
a03be957 2293Bool_t AliAnalysisAlien::SubmitNext()
d2a409b2 2294{
2295// Submit next bunch of master jobs if the queue is free.
2296 static Bool_t iscalled = kFALSE;
2297 static Int_t firstmaster = 0;
2298 static Int_t lastmaster = 0;
2299 static Int_t npermaster = 0;
a03be957 2300 if (iscalled) return kTRUE;
d2a409b2 2301 iscalled = kTRUE;
2302 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2303 Int_t ntosubmit = 0;
2304 TGridResult *res;
2305 TString jobID = "";
2306 if (!fNsubmitted) ntosubmit = 1;
2307 else {
2308 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
84fcd93f 2309 printf("=== master %d: %s\n", lastmaster, status.Data());
d2a409b2 2310 // If last master not split, just return
a03be957 2311 if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
d2a409b2 2312 // No more than 100 waiting jobs
a03be957 2313 if (nwaiting>100) {iscalled = kFALSE; return kTRUE;}
d2a409b2 2314 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
2315 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
7586eedc 2316 if (!ntosubmit) ntosubmit = 1;
84fcd93f 2317 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
d2a409b2 2318 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2319 }
2320 Int_t nmasterjobs = fInputFiles->GetEntries();
2321 for (Int_t i=0; i<ntosubmit; i++) {
2322 // Submit for a range of enumeration of runs.
a03be957 2323 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
d2a409b2 2324 TString query;
cd11251e 2325 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2326 runOutDir.ReplaceAll(".xml", "");
2327 if (fOutputToRunNo)
2328 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2329 else
2330 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
84fcd93f 2331 printf("********* %s\n",query.Data());
d2a409b2 2332 res = gGrid->Command(query);
2333 if (res) {
98ca124f 2334 TString cjobId1 = res->GetKey(0,"jobId");
2335 if (!cjobId1.Length()) {
d2a409b2 2336 iscalled = kFALSE;
a03be957 2337 gGrid->Stdout();
2338 gGrid->Stderr();
2339 Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2340 return kFALSE;
d2a409b2 2341 } else {
2342 Info("StartAnalysis", "\n_______________________________________________________________________ \
2343 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2344 \n_______________________________________________________________________",
98ca124f 2345 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
d2a409b2 2346 jobID += cjobId1;
2347 jobID += " ";
98ca124f 2348 lastmaster = cjobId1.Atoi();
d2a409b2 2349 if (!firstmaster) firstmaster = lastmaster;
2350 fNsubmitted++;
2351 }
2352 delete res;
a03be957 2353 } else {
2354 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2355 return kFALSE;
d2a409b2 2356 }
2357 }
2358 iscalled = kFALSE;
a03be957 2359 return kTRUE;
d2a409b2 2360}
2361
c57f56b7 2362//______________________________________________________________________________
2363void AliAnalysisAlien::WriteAnalysisFile()
2364{
f10e8481 2365// Write current analysis manager into the file <analysisFile>
2366 TString analysisFile = fExecutable;
2367 analysisFile.ReplaceAll(".sh", ".root");
c57f56b7 2368 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2369 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2370 if (!mgr || !mgr->IsInitialized()) {
2371 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2372 return;
2373 }
2374 // Check analysis type
2375 TObject *handler;
2376 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
2377 handler = (TObject*)mgr->GetInputEventHandler();
2378 if (handler) {
2379 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
2380 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
2381 }
2382 TDirectory *cdir = gDirectory;
f10e8481 2383 TFile *file = TFile::Open(analysisFile, "RECREATE");
c57f56b7 2384 if (file) {
e16a394c 2385 // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
2386 if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
fe2d7fc2 2387 // Unless merging makes no sense
2388 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
c57f56b7 2389 mgr->Write();
2390 delete file;
fe2d7fc2 2391 // Enable termination for local jobs
2392 mgr->SetSkipTerminate(kFALSE);
c57f56b7 2393 }
2394 if (cdir) cdir->cd();
f10e8481 2395 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
c57f56b7 2396 }
2397 Bool_t copy = kTRUE;
2398 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2399 if (copy) {
2400 CdWork();
2401 TString workdir = gGrid->GetHomeDirectory();
2402 workdir += fGridWorkingDir;
f10e8481 2403 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
2404 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
2405 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
c57f56b7 2406 }
2407}
2408
2409//______________________________________________________________________________
2410void AliAnalysisAlien::WriteAnalysisMacro()
2411{
2412// Write the analysis macro that will steer the analysis in grid mode.
2413 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2414 ofstream out;
2415 out.open(fAnalysisMacro.Data(), ios::out);
2416 if (!out.good()) {
2417 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2418 return;
2419 }
5b273635 2420 Bool_t hasSTEERBase = kFALSE;
2421 Bool_t hasESD = kFALSE;
2422 Bool_t hasAOD = kFALSE;
2423 Bool_t hasANALYSIS = kFALSE;
2424 Bool_t hasANALYSISalice = kFALSE;
2425 Bool_t hasCORRFW = kFALSE;
c57f56b7 2426 TString func = fAnalysisMacro;
2427 TString type = "ESD";
2428 TString comment = "// Analysis using ";
2429 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2430 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2431 type = "AOD";
2432 comment += "AOD";
2433 }
0df6ccf2 2434 if (type!="AOD" && fFriendChainName!="") {
2435 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2436 return;
2437 }
c57f56b7 2438 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2439 else comment += " data";
2440 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2441 func.ReplaceAll(".C", "");
2442 out << "void " << func.Data() << "()" << endl;
2443 out << "{" << endl;
2444 out << comment.Data() << endl;
2445 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
f7498086 2446 out << " TStopwatch timer;" << endl;
2447 out << " timer.Start();" << endl << endl;
c57f56b7 2448 out << "// load base root libraries" << endl;
2449 out << " gSystem->Load(\"libTree\");" << endl;
2450 out << " gSystem->Load(\"libGeom\");" << endl;
2451 out << " gSystem->Load(\"libVMC\");" << endl;
2452 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
648174cf 2453 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
d5c6455a 2454 if (fAdditionalRootLibs.Length()) {
47a4137d 2455 // in principle libtree /lib geom libvmc etc. can go into this list, too
2456 out << "// Add aditional libraries" << endl;
2457 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2458 TIter next(list);
2459 TObjString *str;
2460 while((str=(TObjString*)next())) {
2461 if (str->GetString().Contains(".so"))
2462 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
d5c6455a 2463 }
47a4137d 2464 if (list) delete list;
d5c6455a 2465 }
47a4137d 2466 out << "// include path" << endl;
2467 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2468 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
57377eb5 2469 out << "// Load analysis framework libraries" << endl;
652561d5 2470 TString setupPar = "AliAnalysisAlien::SetupPar";
4e5c5506 2471 if (!fPackages) {
4e5c5506 2472 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2473 out << " gSystem->Load(\"libESD\");" << endl;
2474 out << " gSystem->Load(\"libAOD\");" << endl;
2475 out << " gSystem->Load(\"libANALYSIS\");" << endl;
57377eb5 2476 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2477 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
4e5c5506 2478 } else {
4e5c5506 2479 TIter next(fPackages);
2480 TObject *obj;
57377eb5 2481 TString pkgname;
57377eb5 2482 while ((obj=next())) {
2483 pkgname = obj->GetName();
4478e6f1 2484 if (pkgname == "STEERBase" ||
2485 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2486 if (pkgname == "ESD" ||
2487 pkgname == "ESD.par") hasESD = kTRUE;
2488 if (pkgname == "AOD" ||
2489 pkgname == "AOD.par") hasAOD = kTRUE;
2490 if (pkgname == "ANALYSIS" ||
2491 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
2492 if (pkgname == "ANALYSISalice" ||
2493 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2494 if (pkgname == "CORRFW" ||
2495 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
5b273635 2496 }
2497 if (hasANALYSISalice) setupPar = "SetupPar";
57377eb5 2498 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
5b273635 2499 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
57377eb5 2500 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
5b273635 2501 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
57377eb5 2502 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
5b273635 2503 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
57377eb5 2504 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
5b273635 2505 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
57377eb5 2506 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
5b273635 2507 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
57377eb5 2508 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
5b273635 2509 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
57377eb5 2510 out << "// Compile other par packages" << endl;
2511 next.Reset();
fcc9bb6f 2512 while ((obj=next())) {
2513 pkgname = obj->GetName();
4478e6f1 2514 if (pkgname == "STEERBase" ||
2515 pkgname == "STEERBase.par" ||
2516 pkgname == "ESD" ||
2517 pkgname == "ESD.par" ||
2518 pkgname == "AOD" ||
2519 pkgname == "AOD.par" ||
2520 pkgname == "ANALYSIS" ||
2521 pkgname == "ANALYSIS.par" ||
2522 pkgname == "ANALYSISalice" ||
2523 pkgname == "ANALYSISalice.par" ||
2524 pkgname == "CORRFW" ||
2525 pkgname == "CORRFW.par") continue;
5b273635 2526 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
fcc9bb6f 2527 }
4e5c5506 2528 }
6da75e0b 2529 if (fAdditionalLibs.Length()) {
2530 out << "// Add aditional AliRoot libraries" << endl;
2531 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2532 TIter next(list);
2533 TObjString *str;
2534 while((str=(TObjString*)next())) {
2535 if (str->GetString().Contains(".so"))
2536 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
652561d5 2537 if (str->GetString().Contains(".par"))
2538 out << " if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
6da75e0b 2539 }
2540 if (list) delete list;
2541 }
2542 out << endl;
c57f56b7 2543 out << "// analysis source to be compiled at runtime (if any)" << endl;
2544 if (fAnalysisSource.Length()) {
2545 TObjArray *list = fAnalysisSource.Tokenize(" ");
2546 TIter next(list);
2547 TObjString *str;
2548 while((str=(TObjString*)next())) {
2549 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2550 }
2551 if (list) delete list;
2552 }
2553 out << endl;
0f389141 2554 if (fFastReadOption) {
d3339be3 2555 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 !!! \
2556 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
0f389141 2557 out << "// fast xrootd reading enabled" << endl;
2558 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 2559 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2560 out << " gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
0f389141 2561 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
d3339be3 2562 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
0f389141 2563 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2564 }
e8b839ab 2565 // Change temp directory to current one
2566 out << "// Set temporary merging directory to current one" << endl;
2567 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
c57f56b7 2568 out << "// connect to AliEn and make the chain" << endl;
2569 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
2570 if (IsUsingTags()) {
2571 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2572 } else {
45e980c4 2573 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
c57f56b7 2574 }
2575 out << "// read the analysis manager from file" << endl;
f10e8481 2576 TString analysisFile = fExecutable;
2577 analysisFile.ReplaceAll(".sh", ".root");
2578 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
c57f56b7 2579 out << " if (!file) return;" << endl;
2580 out << " TIter nextkey(file->GetListOfKeys());" << endl;
2581 out << " AliAnalysisManager *mgr = 0;" << endl;
2582 out << " TKey *key;" << endl;
2583 out << " while ((key=(TKey*)nextkey())) {" << endl;
2584 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2585 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2586 out << " };" << endl;
2587 out << " if (!mgr) {" << endl;
205b201f 2588 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file " << analysisFile <<"\");" << endl;
c57f56b7 2589 out << " return;" << endl;
2590 out << " }" << endl << endl;
2591 out << " mgr->PrintStatus();" << endl;
52b6a92b 2592 if (AliAnalysisManager::GetAnalysisManager()) {
f866cba5 2593 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
52b6a92b 2594 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
de52b69c 2595 } else {
2596 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
52b6a92b 2597 }
2598 }
c57f56b7 2599 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
f7498086 2600 out << " timer.Stop();" << endl;
2601 out << " timer.Print();" << endl;
c57f56b7 2602 out << "}" << endl << endl;
2603 if (IsUsingTags()) {
2604 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2605 out << "{" << endl;
2606 out << "// Create a chain using tags from the xml file." << endl;
2607 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2608 out << " if (!coll) {" << endl;
2609 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2610 out << " return NULL;" << endl;
2611 out << " }" << endl;
2612 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2613 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2614 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
2615 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
2616 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
2617 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2618 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
2619 out << " // Check if the cuts configuration file was provided" << endl;
2620 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2621 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2622 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2623 out << " }" << endl;
0df6ccf2 2624 if (fFriendChainName=="") {
2625 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2626 } else {
2627 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
2628 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2629 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2630 }
c57f56b7 2631 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2632 out << " chain->ls();" << endl;
2633 out << " return chain;" << endl;
fcc9bb6f 2634 out << "}" << endl << endl;
c57f56b7 2635 if (gSystem->AccessPathName("ConfigureCuts.C")) {
2636 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
2637 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2638 msg += " AliLHCTagCuts *lhcCuts,\n";
2639 msg += " AliDetectorTagCuts *detCuts,\n";
2640 msg += " AliEventTagCuts *evCuts)";
2641 Info("WriteAnalysisMacro", msg.Data());
2642 }
0df6ccf2 2643 }
2644 if (!IsUsingTags() || fFriendChainName!="") {
fcc9bb6f 2645 out <<"//________________________________________________________________________________" << endl;
c57f56b7 2646 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2647 out << "{" << endl;
2648 out << "// Create a chain using url's from xml file" << endl;
2649 out << " TString treename = type;" << endl;
2650 out << " treename.ToLower();" << endl;
2651 out << " treename += \"Tree\";" << endl;
e02fee64 2652 out << " printf(\"***************************************\\n\");" << endl;
2653 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
2654 out << " printf(\"***************************************\\n\");" << endl;
c57f56b7 2655 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2656 out << " if (!coll) {" << endl;
2657 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2658 out << " return NULL;" << endl;
2659 out << " }" << endl;
2660 out << " TChain *chain = new TChain(treename);" << endl;
0df6ccf2 2661 if(fFriendChainName!="") {
2662 out << " TChain *chainFriend = new TChain(treename);" << endl;
2663 }
c57f56b7 2664 out << " coll->Reset();" << endl;
0df6ccf2 2665 out << " while (coll->Next()) {" << endl;
2666 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
2667 if(fFriendChainName!="") {
2668 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
2669 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2670 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2671 out << " chainFriend->Add(fileFriend.Data());" << endl;
2672 }
2673 out << " }" << endl;
c57f56b7 2674 out << " if (!chain->GetNtrees()) {" << endl;
2675 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2676 out << " return NULL;" << endl;
2677 out << " }" << endl;
0df6ccf2 2678 if(fFriendChainName!="") {
2679 out << " chain->AddFriend(chainFriend);" << endl;
2680 }
c57f56b7 2681 out << " return chain;" << endl;
fcc9bb6f 2682 out << "}" << endl << endl;
c57f56b7 2683 }
5b273635 2684 if (hasANALYSISalice) {
2685 out <<"//________________________________________________________________________________" << endl;
2686 out << "Bool_t SetupPar(const char *package) {" << endl;
2687 out << "// Compile the package and set it up." << endl;
2688 out << " TString pkgdir = package;" << endl;
2689 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2690 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2691 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2692 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2693 out << " // Check for BUILD.sh and execute" << endl;
2694 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2695 out << " printf(\"*******************************\\n\");" << endl;
2696 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2697 out << " printf(\"*******************************\\n\");" << endl;
2698 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2699 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2700 out << " gSystem->ChangeDirectory(cdir);" << endl;
2701 out << " return kFALSE;" << endl;
2702 out << " }" << endl;
2703 out << " } else {" << endl;
2704 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2705 out << " gSystem->ChangeDirectory(cdir);" << endl;
2706 out << " return kFALSE;" << endl;
2707 out << " }" << endl;
2708 out << " // Check for SETUP.C and execute" << endl;
2709 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2710 out << " printf(\"*******************************\\n\");" << endl;
2711 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2712 out << " printf(\"*******************************\\n\");" << endl;
2713 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2714 out << " } else {" << endl;
2715 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2716 out << " gSystem->ChangeDirectory(cdir);" << endl;
2717 out << " return kFALSE;" << endl;
2718 out << " }" << endl;
2719 out << " // Restore original workdir" << endl;
2720 out << " gSystem->ChangeDirectory(cdir);" << endl;
2721 out << " return kTRUE;" << endl;
2722 out << "}" << endl;
2723 }
c57f56b7 2724 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2725 }
2726 Bool_t copy = kTRUE;
2727 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2728 if (copy) {
2729 CdWork();
2730 TString workdir = gGrid->GetHomeDirectory();
2731 workdir += fGridWorkingDir;
2732 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2733 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2734 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2735 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2736 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2737 }
2738 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2739 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2740 }
2741}
2742
0f389141 2743//______________________________________________________________________________
2744void AliAnalysisAlien::WriteMergingMacro()
2745{
2746// Write a macro to merge the outputs per master job.
2747 if (!fMergeViaJDL) return;
2748 if (!fOutputFiles.Length()) {
2749 Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2750 return;
2751 }
2752 TString mergingMacro = fExecutable;
2753 mergingMacro.ReplaceAll(".sh","_merge.C");
2754 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2755 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2756 ofstream out;
2757 out.open(mergingMacro.Data(), ios::out);
2758 if (!out.good()) {
2759 Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2760 return;
2761 }
5b273635 2762 Bool_t hasSTEERBase = kFALSE;
2763 Bool_t hasESD = kFALSE;
2764 Bool_t hasAOD = kFALSE;
2765 Bool_t hasANALYSIS = kFALSE;
2766 Bool_t hasANALYSISalice = kFALSE;
2767 Bool_t hasCORRFW = kFALSE;
0f389141 2768 TString func = mergingMacro;
2769 TString comment;
2770 func.ReplaceAll(".C", "");
7c2cd90a 2771 out << "void " << func.Data() << "(const char *dir, Int_t stage=0, Int_t ichunk=0)" << endl;
0f389141 2772 out << "{" << endl;
2773 out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
2774 out << " TStopwatch timer;" << endl;
2775 out << " timer.Start();" << endl << endl;
7c2cd90a 2776 if (!fExecutableCommand.Contains("aliroot")) {
2777 out << "// load base root libraries" << endl;
2778 out << " gSystem->Load(\"libTree\");" << endl;
2779 out << " gSystem->Load(\"libGeom\");" << endl;
2780 out << " gSystem->Load(\"libVMC\");" << endl;
2781 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
2782 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
2783 }
0f389141 2784 if (fAdditionalRootLibs.Length()) {
2785 // in principle libtree /lib geom libvmc etc. can go into this list, too
2786 out << "// Add aditional libraries" << endl;
2787 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2788 TIter next(list);
2789 TObjString *str;
2790 while((str=(TObjString*)next())) {
2791 if (str->GetString().Contains(".so"))
2792 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2793 }
2794 if (list) delete list;
2795 }
2796 out << "// include path" << endl;
2797 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2798 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2799 out << "// Load analysis framework libraries" << endl;
2800 if (!fPackages) {
7c2cd90a 2801 if (!fExecutableCommand.Contains("aliroot")) {
2802 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2803 out << " gSystem->Load(\"libESD\");" << endl;
2804 out << " gSystem->Load(\"libAOD\");" << endl;
2805 }
0f389141 2806 out << " gSystem->Load(\"libANALYSIS\");" << endl;
2807 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2808 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
2809 } else {
2810 TIter next(fPackages);
2811 TObject *obj;
2812 TString pkgname;
5b273635 2813 TString setupPar = "AliAnalysisAlien::SetupPar";
0f389141 2814 while ((obj=next())) {
2815 pkgname = obj->GetName();
2816 if (pkgname == "STEERBase" ||
2817 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2818 if (pkgname == "ESD" ||
2819 pkgname == "ESD.par") hasESD = kTRUE;
2820 if (pkgname == "AOD" ||
2821 pkgname == "AOD.par") hasAOD = kTRUE;
2822 if (pkgname == "ANALYSIS" ||
2823 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
2824 if (pkgname == "ANALYSISalice" ||
2825 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2826 if (pkgname == "CORRFW" ||
2827 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
2828 }
5b273635 2829 if (hasANALYSISalice) setupPar = "SetupPar";
0f389141 2830 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
5b273635 2831 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
0f389141 2832 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
5b273635 2833 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
0f389141 2834 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
5b273635 2835 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
0f389141 2836 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
5b273635 2837 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
0f389141 2838 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
5b273635 2839 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
0f389141 2840 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
5b273635 2841 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
0f389141 2842 out << "// Compile other par packages" << endl;
2843 next.Reset();
2844 while ((obj=next())) {
2845 pkgname = obj->GetName();
2846 if (pkgname == "STEERBase" ||
2847 pkgname == "STEERBase.par" ||
2848 pkgname == "ESD" ||
2849 pkgname == "ESD.par" ||
2850 pkgname == "AOD" ||
2851 pkgname == "AOD.par" ||
2852 pkgname == "ANALYSIS" ||
2853 pkgname == "ANALYSIS.par" ||
2854 pkgname == "ANALYSISalice" ||
2855 pkgname == "ANALYSISalice.par" ||
2856 pkgname == "CORRFW" ||
2857 pkgname == "CORRFW.par") continue;
5b273635 2858 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
0f389141 2859 }
2860 }
2861 if (fAdditionalLibs.Length()) {
2862 out << "// Add aditional AliRoot libraries" << endl;
2863 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2864 TIter next(list);
2865 TObjString *str;
2866 while((str=(TObjString*)next())) {
2867 if (str->GetString().Contains(".so"))
2868 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2869 }
2870 if (list) delete list;
2871 }
2872 out << endl;
2873 out << "// Analysis source to be compiled at runtime (if any)" << endl;
2874 if (fAnalysisSource.Length()) {
2875 TObjArray *list = fAnalysisSource.Tokenize(" ");
2876 TIter next(list);
2877 TObjString *str;
2878 while((str=(TObjString*)next())) {
2879 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2880 }
2881 if (list) delete list;
2882 }
149d288c 2883 out << endl;
2884
0f389141 2885 if (fFastReadOption) {
2886 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 !!!");
2887 out << "// fast xrootd reading enabled" << endl;
2888 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 2889 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2890 out << " gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
0f389141 2891 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
d3339be3 2892 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
0f389141 2893 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
e8b839ab 2894 }
2895 // Change temp directory to current one
2896 out << "// Set temporary merging directory to current one" << endl;
2897 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
0f389141 2898 out << "// Connect to AliEn" << endl;
2899 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
0cdf65a8 2900 out << " Bool_t laststage = kFALSE;" << endl;
7c2cd90a 2901 out << " TString outputDir = dir;" << endl;
0f389141 2902 out << " TString outputFiles = \"" << fOutputFiles << "\";" << endl;
2903 out << " TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
1f0d1ca2 2904 out << " mergeExcludes += \"" << AliAnalysisManager::GetAnalysisManager()->GetExtraFiles() << "\";" << endl;
58268c13 2905 out << " TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
0f389141 2906 out << " TIter *iter = new TIter(list);" << endl;
2907 out << " TObjString *str;" << endl;
a2f5fc01 2908 out << " TString outputFile;" << endl;
0f389141 2909 out << " Bool_t merged = kTRUE;" << endl;
2910 out << " while((str=(TObjString*)iter->Next())) {" << endl;
a2f5fc01 2911 out << " outputFile = str->GetString();" << endl;
7c2cd90a 2912 out << " if (outputFile.Contains(\"*\")) continue;" << endl;
a2f5fc01 2913 out << " Int_t index = outputFile.Index(\"@\");" << endl;
2914 out << " if (index > 0) outputFile.Remove(index);" << endl;
0f389141 2915 out << " // Skip already merged outputs" << endl;
a2f5fc01 2916 out << " if (!gSystem->AccessPathName(outputFile)) {" << endl;
2917 out << " printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
0f389141 2918 out << " continue;" << endl;
2919 out << " }" << endl;
a2f5fc01 2920 out << " if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
7c2cd90a 2921 out << " merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage, ichunk);" << endl;
0f389141 2922 out << " if (!merged) {" << endl;
a2f5fc01 2923 out << " printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
7c2cd90a 2924 out << " return;" << endl;
0f389141 2925 out << " }" << endl;
7c2cd90a 2926 out << " // Check if this was the last stage. If yes, run terminate for the tasks." << endl;
2927 out << " if (!gSystem->AccessPathName(outputFile)) laststage = kTRUE;" << endl;
0f389141 2928 out << " }" << endl;
7c2cd90a 2929 out << " // all outputs merged, validate" << endl;
2930 out << " ofstream out;" << endl;
2931 out << " out.open(\"outputs_valid\", ios::out);" << endl;
2932 out << " out.close();" << endl;
2933 out << " // read the analysis manager from file" << endl;
f866cba5 2934 TString analysisFile = fExecutable;
2935 analysisFile.ReplaceAll(".sh", ".root");
7c2cd90a 2936 out << " if (!laststage) return;" << endl;
f866cba5 2937 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
7c2cd90a 2938 out << " if (!file) return;" << endl;
f866cba5 2939 out << " TIter nextkey(file->GetListOfKeys());" << endl;
2940 out << " AliAnalysisManager *mgr = 0;" << endl;
2941 out << " TKey *key;" << endl;
2942 out << " while ((key=(TKey*)nextkey())) {" << endl;
2943 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2944 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2945 out << " };" << endl;
2946 out << " if (!mgr) {" << endl;
2947 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2948 out << " return;" << endl;
2949 out << " }" << endl << endl;
b385fec0 2950 out << " mgr->SetSkipTerminate(kFALSE);" << endl;
f866cba5 2951 out << " mgr->PrintStatus();" << endl;
2952 if (AliAnalysisManager::GetAnalysisManager()) {
2953 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2954 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2955 } else {
2956 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2957 }
2958 }
2959 out << " mgr->StartAnalysis(\"gridterminate\");" << endl;
0f389141 2960 out << "}" << endl << endl;
5b273635 2961 if (hasANALYSISalice) {
2962 out <<"//________________________________________________________________________________" << endl;
2963 out << "Bool_t SetupPar(const char *package) {" << endl;
2964 out << "// Compile the package and set it up." << endl;
2965 out << " TString pkgdir = package;" << endl;
2966 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2967 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2968 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2969 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2970 out << " // Check for BUILD.sh and execute" << endl;
2971 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2972 out << " printf(\"*******************************\\n\");" << endl;
2973 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2974 out << " printf(\"*******************************\\n\");" << endl;
2975 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2976 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2977 out << " gSystem->ChangeDirectory(cdir);" << endl;
2978 out << " return kFALSE;" << endl;
2979 out << " }" << endl;
2980 out << " } else {" << endl;
2981 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2982 out << " gSystem->ChangeDirectory(cdir);" << endl;
2983 out << " return kFALSE;" << endl;
2984 out << " }" << endl;
2985 out << " // Check for SETUP.C and execute" << endl;
2986 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2987 out << " printf(\"*******************************\\n\");" << endl;
2988 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2989 out << " printf(\"*******************************\\n\");" << endl;
2990 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2991 out << " } else {" << endl;
2992 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2993 out << " gSystem->ChangeDirectory(cdir);" << endl;
2994 out << " return kFALSE;" << endl;
2995 out << " }" << endl;
2996 out << " // Restore original workdir" << endl;
2997 out << " gSystem->ChangeDirectory(cdir);" << endl;
2998 out << " return kTRUE;" << endl;
2999 out << "}" << endl;
3000 }
0f389141 3001 }
3002 Bool_t copy = kTRUE;
3003 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3004 if (copy) {
3005 CdWork();
3006 TString workdir = gGrid->GetHomeDirectory();
3007 workdir += fGridWorkingDir;
3008 if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
3009 Info("WriteMergingMacro", "\n##### Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
3010 TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
3011 }
3012}
3013
3014//______________________________________________________________________________
3015Bool_t AliAnalysisAlien::SetupPar(const char *package)
3016{
205b201f 3017// Compile the par file archive pointed by <package>. This must be present in the current directory.
0f389141 3018// Note that for loading the compiled library. The current directory should have precedence in
3019// LD_LIBRARY_PATH
3020 TString pkgdir = package;
3021 pkgdir.ReplaceAll(".par","");
3022 gSystem->Exec(Form("tar xvzf %s.par", pkgdir.Data()));
3023 TString cdir = gSystem->WorkingDirectory();
3024 gSystem->ChangeDirectory(pkgdir);
3025 // Check for BUILD.sh and execute
3026 if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
3027 printf("**************************************************\n");
3028 printf("*** Building PAR archive %s\n", package);
3029 printf("**************************************************\n");
3030 if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
3031 ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
3032 gSystem->ChangeDirectory(cdir);
3033 return kFALSE;
3034 }
3035 } else {
3036 ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
3037 gSystem->ChangeDirectory(cdir);
3038 return kFALSE;
3039 }
3040 // Check for SETUP.C and execute
3041 if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
3042 printf("**************************************************\n");
3043 printf("*** Setup PAR archive %s\n", package);
3044 printf("**************************************************\n");
3045 gROOT->Macro("PROOF-INF/SETUP.C");
3046 printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
3047 } else {
3048 ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
3049 gSystem->ChangeDirectory(cdir);
3050 return kFALSE;
3051 }
3052 // Restore original workdir
3053 gSystem->ChangeDirectory(cdir);
3054 return kTRUE;
3055}
3056
c57f56b7 3057//______________________________________________________________________________
3058void AliAnalysisAlien::WriteExecutable()
3059{
3060// Generate the alien executable script.
3061 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3062 ofstream out;
3063 out.open(fExecutable.Data(), ios::out);
3064 if (out.bad()) {
5513444a 3065 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
c57f56b7 3066 return;
3067 }
3068 out << "#!/bin/bash" << endl;
c57f56b7 3069 out << "echo \"=========================================\"" << endl;
3070 out << "echo \"############## PATH : ##############\"" << endl;
3071 out << "echo $PATH" << endl;
3072 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3073 out << "echo $LD_LIBRARY_PATH" << endl;
3074 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3075 out << "echo $ROOTSYS" << endl;
3076 out << "echo \"############## which root : ##############\"" << endl;
3077 out << "which root" << endl;
3078 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3079 out << "echo $ALICE_ROOT" << endl;
3080 out << "echo \"############## which aliroot : ##############\"" << endl;
3081 out << "which aliroot" << endl;
9c5ddadc 3082 out << "echo \"############## system limits : ##############\"" << endl;
3083 out << "ulimit -a" << endl;
3084 out << "echo \"############## memory : ##############\"" << endl;
3085 out << "free -m" << endl;
c57f56b7 3086 out << "echo \"=========================================\"" << endl << endl;
74a53467 3087 // Make sure we can properly compile par files
3088 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
0a1c1f7f 3089 out << fExecutableCommand << " ";
631c0b05 3090 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
9c5ddadc 3091 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
3092 out << "echo \"############## memory after: ##############\"" << endl;
3093 out << "free -m" << endl;
c57f56b7 3094 }
3095 Bool_t copy = kTRUE;
3096 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3097 if (copy) {
3098 CdWork();
3099 TString workdir = gGrid->GetHomeDirectory();
923e2ca5 3100 TString bindir = Form("%s/bin", workdir.Data());
b93f8109 3101 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
c57f56b7 3102 workdir += fGridWorkingDir;
3103 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
3104 if (FileExists(executable)) gGrid->Rm(executable);
3105 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
3106 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
3107 }
3108}
3109
0f389141 3110//______________________________________________________________________________
3111void AliAnalysisAlien::WriteMergeExecutable()
3112{
3113// Generate the alien executable script for the merging job.
3114 if (!fMergeViaJDL) return;
3115 TString mergeExec = fExecutable;
3116 mergeExec.ReplaceAll(".sh", "_merge.sh");
3117 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3118 ofstream out;
3119 out.open(mergeExec.Data(), ios::out);
3120 if (out.bad()) {
3121 Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
3122 return;
3123 }
3124 out << "#!/bin/bash" << endl;
3125 out << "echo \"=========================================\"" << endl;
3126 out << "echo \"############## PATH : ##############\"" << endl;
3127 out << "echo $PATH" << endl;
3128 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3129 out << "echo $LD_LIBRARY_PATH" << endl;
3130 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3131 out << "echo $ROOTSYS" << endl;
3132 out << "echo \"############## which root : ##############\"" << endl;
3133 out << "which root" << endl;
3134 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3135 out << "echo $ALICE_ROOT" << endl;
3136 out << "echo \"############## which aliroot : ##############\"" << endl;
3137 out << "which aliroot" << endl;
3138 out << "echo \"############## system limits : ##############\"" << endl;
3139 out << "ulimit -a" << endl;
3140 out << "echo \"############## memory : ##############\"" << endl;
3141 out << "free -m" << endl;
3142 out << "echo \"=========================================\"" << endl << endl;
3143 // Make sure we can properly compile par files
3144 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3145 TString mergeMacro = fExecutable;
3146 mergeMacro.ReplaceAll(".sh", "_merge.C");
7c2cd90a 3147 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2,$3)\"" << endl;
0f389141 3148 out << fExecutableCommand << " " << "$ARG" << endl;
3149 out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
3150 out << "echo \"############## memory after: ##############\"" << endl;
3151 out << "free -m" << endl;
0f389141 3152 }
3153 Bool_t copy = kTRUE;
3154 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3155 if (copy) {
3156 CdWork();
3157 TString workdir = gGrid->GetHomeDirectory();
3158 TString bindir = Form("%s/bin", workdir.Data());
b93f8109 3159 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
0f389141 3160 workdir += fGridWorkingDir;
3161 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
3162 if (FileExists(executable)) gGrid->Rm(executable);
3163 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
3164 TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
3165 }
3166}
3167
c57f56b7 3168//______________________________________________________________________________
5513444a 3169void AliAnalysisAlien::WriteProductionFile(const char *filename) const
3170{
3171// Write the production file to be submitted by LPM manager. The format is:
f5e8c702 3172// First line: full_path_to_jdl estimated_no_subjobs_per_master
5513444a 3173// Next lines: full_path_to_dataset XXX (XXX is a string)
3174// To submit, one has to: submit jdl XXX for all lines
3175 ofstream out;
3176 out.open(filename, ios::out);
3177 if (out.bad()) {
3178 Error("WriteProductionFile", "Bad file name: %s", filename);
3179 return;
3180 }
3181 TString workdir = gGrid->GetHomeDirectory();
3182 workdir += fGridWorkingDir;
f5e8c702 3183 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
5513444a 3184 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
f5e8c702 3185 out << locjdl << " " << njobspermaster << endl;
5513444a 3186 Int_t nmasterjobs = fInputFiles->GetEntries();
3187 for (Int_t i=0; i<nmasterjobs; i++) {
409b4ada 3188 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3189 runOutDir.ReplaceAll(".xml", "");
3190 if (fOutputToRunNo)
3191 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
3192 else
3193 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
5513444a 3194 }
3195 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
fdbbc7be 3196 if (FileExists(filename)) gGrid->Rm(filename);
5513444a 3197 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
3198}
3199
3200//______________________________________________________________________________
0f389141 3201void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
c57f56b7 3202{
3203// Generate the alien validation script.
3204 // Generate the validation script
3205 TObjString *os;
0d5d317c 3206 TString validationScript = fExecutable;
0f389141 3207 if (merge) validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
3208 else validationScript.ReplaceAll(".sh", "_validation.sh");
c57f56b7 3209 if (!Connect()) {
3210 Error("WriteValidationScript", "Alien connection required");
3211 return;
3212 }
a2f5fc01 3213 TString outStream = "";
3214 if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
c57f56b7 3215 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3216 ofstream out;
0d5d317c 3217 out.open(validationScript, ios::out);
c57f56b7 3218 out << "#!/bin/bash" << endl;
3219 out << "##################################################" << endl;
3220 out << "validateout=`dirname $0`" << endl;
3221 out << "validatetime=`date`" << endl;
3222 out << "validated=\"0\";" << endl;
3223 out << "error=0" << endl;
3224 out << "if [ -z $validateout ]" << endl;
3225 out << "then" << endl;
3226 out << " validateout=\".\"" << endl;
3227 out << "fi" << endl << endl;
3228 out << "cd $validateout;" << endl;
3229 out << "validateworkdir=`pwd`;" << endl << endl;
a2f5fc01 3230 out << "echo \"*******************************************************\"" << outStream << endl;
3231 out << "echo \"* Automatically generated validation script *\"" << outStream << endl;
c57f56b7 3232 out << "" << endl;
a2f5fc01 3233 out << "echo \"* Time: $validatetime \"" << outStream << endl;
3234 out << "echo \"* Dir: $validateout\"" << outStream << endl;
3235 out << "echo \"* Workdir: $validateworkdir\"" << outStream << endl;
3236 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3237 out << "ls -la ./" << outStream << endl;
3238 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl << endl;
c57f56b7 3239 out << "##################################################" << endl;
ebec370a 3240 out << "" << endl;
3241
3242 out << "if [ ! -f stderr ] ; then" << endl;
3243 out << " error=1" << endl;
a2f5fc01 3244 out << " echo \"* ########## Job not validated - no stderr ###\" " << outStream << endl;
3245 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3246 out << "fi" << endl;
3247
b34c9f51 3248 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
3249 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
3250 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
3251 out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
3252 out << "" << endl;
3253
ebec370a 3254 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
3255 out << " error=1" << endl;
a2f5fc01 3256 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << outStream << endl;
3257 out << " echo \"$parArch\" " << outStream << endl;
3258 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3259 out << "fi" << endl;
3260
3261 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
3262 out << " error=1" << endl;
a2f5fc01 3263 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << outStream << endl;
3264 out << " echo \"$segViol\" " << outStream << endl;
3265 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3266 out << "fi" << endl;
3267
3268 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
3269 out << " error=1" << endl;
a2f5fc01 3270 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << outStream << endl;
3271 out << " echo \"$segFault\" " << outStream << endl;
3272 out << " echo \"Error = $error\" " << outStream << endl;
ebec370a 3273 out << "fi" << endl;
3274
b34c9f51 3275 out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
3276 out << " error=1" << endl;
a2f5fc01 3277 out << " echo \"* ########## Job not validated - *** glibc detected *** ###\" " << outStream << endl;
3278 out << " echo \"$glibcErr\" " << outStream << endl;
3279 out << " echo \"Error = $error\" " << outStream << endl;
b34c9f51 3280 out << "fi" << endl;
3281
ebec370a 3282 // Part dedicated to the specific analyses running into the train
3283
149d288c 3284 TObjArray *arr = fOutputFiles.Tokenize(",");
c57f56b7 3285 TIter next1(arr);
a2f5fc01 3286 TString outputFile;
5b9b4998 3287 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3288 TString extra = mgr->GetExtraFiles();
c57f56b7 3289 while ((os=(TObjString*)next1())) {
7c2cd90a 3290 if (merge) break;
a2f5fc01 3291 outputFile = os->GetString();
3292 Int_t index = outputFile.Index("@");
3293 if (index > 0) outputFile.Remove(index);
3294 if (merge && fMergeExcludes.Contains(outputFile)) continue;
3295 if (extra.Contains(outputFile)) continue;
3296 if (outputFile.Contains("*")) continue;
3297 out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
c57f56b7 3298 out << " error=1" << endl;
7c2cd90a 3299 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\"" << outStream << endl;
3300 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
c57f56b7 3301 out << "fi" << endl;
3302 }
3303 delete arr;
7c2cd90a 3304 out << "if ! [ -f outputs_valid ] ; then" << endl;
3305 out << " error=1" << endl;
3306 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
3307 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
3308 out << "fi" << endl;
923e2ca5 3309
c57f56b7 3310 out << "if [ $error = 0 ] ; then" << endl;
a2f5fc01 3311 out << " echo \"* ---------------- Job Validated ------------------*\"" << outStream << endl;
149d288c 3312 if (!IsKeepLogs()) {
3313 out << " echo \"* === Logs std* will be deleted === \"" << endl;
a2f5fc01 3314 outStream = "";
149d288c 3315 out << " rm -f std*" << endl;
3316 }
c57f56b7 3317 out << "fi" << endl;
3318
a2f5fc01 3319 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3320 out << "echo \"*******************************************************\"" << outStream << endl;
c57f56b7 3321 out << "cd -" << endl;
3322 out << "exit $error" << endl;
3323 }
3324 Bool_t copy = kTRUE;
3325 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3326 if (copy) {
3327 CdWork();
3328 TString workdir = gGrid->GetHomeDirectory();
3329 workdir += fGridWorkingDir;
0d5d317c 3330 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
3331 if (FileExists(validationScript)) gGrid->Rm(validationScript);
3332 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
c57f56b7 3333 }
3334}