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