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