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