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