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