bugfix: correct handling of empty rows in TPC digit data, bug #50771
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisAlien.cxx
CommitLineData
c57f56b7 1/**************************************************************************
2 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
16// Author: Mihaela Gheata, 01/09/2008
17
18//==============================================================================
19// AliAnalysisAlien - AliEn utility class. Provides interface for creating
20// a personalized JDL, finding and creating a dataset.
21//==============================================================================
22
23#include "Riostream.h"
24#include "TROOT.h"
25#include "TSystem.h"
26#include "TFile.h"
27#include "TObjString.h"
28#include "TObjArray.h"
29#include "TGrid.h"
30#include "TGridResult.h"
31#include "TGridCollection.h"
32#include "TGridJDL.h"
33#include "TFileMerger.h"
34#include "AliAnalysisManager.h"
bb885a9e 35#include "AliVEventHandler.h"
36#include "AliAnalysisDataContainer.h"
c57f56b7 37#include "AliAnalysisAlien.h"
38
39ClassImp(AliAnalysisAlien)
40
41//______________________________________________________________________________
42AliAnalysisAlien::AliAnalysisAlien()
43 :AliAnalysisGrid(),
44 fGridJDL(NULL),
45 fPrice(0),
46 fTTL(0),
47 fSplitMaxInputFileNumber(0),
48 fMaxInitFailed(0),
49 fMasterResubmitThreshold(0),
bb885a9e 50 fNtestFiles(0),
c57f56b7 51 fRunNumbers(),
52 fExecutable(),
53 fArguments(),
54 fAnalysisMacro(),
55 fAnalysisSource(),
56 fAdditionalLibs(),
57 fSplitMode(),
58 fAPIVersion(),
59 fROOTVersion(),
60 fAliROOTVersion(),
61 fUser(),
62 fGridWorkingDir(),
63 fGridDataDir(),
64 fDataPattern(),
65 fGridOutputDir(),
66 fOutputArchive(),
67 fOutputFiles(),
68 fInputFormat(),
e7c71df0 69 fDatasetName(),
c57f56b7 70 fJDLName(),
bb885a9e 71 fMergeExcludes(),
f965131e 72 fIncludePath(),
bb885a9e 73 fCloseSE(),
0df6ccf2 74 fFriendChainName(),
4e5c5506 75 fInputFiles(0),
76 fPackages(0)
c57f56b7 77{
78// Dummy ctor.
79 SetDefaults();
80}
81
82//______________________________________________________________________________
83AliAnalysisAlien::AliAnalysisAlien(const char *name)
84 :AliAnalysisGrid(name),
85 fGridJDL(NULL),
86 fPrice(0),
87 fTTL(0),
88 fSplitMaxInputFileNumber(0),
89 fMaxInitFailed(0),
90 fMasterResubmitThreshold(0),
bb885a9e 91 fNtestFiles(0),
c57f56b7 92 fRunNumbers(),
93 fExecutable(),
94 fArguments(),
95 fAnalysisMacro(),
96 fAnalysisSource(),
97 fAdditionalLibs(),
98 fSplitMode(),
99 fAPIVersion(),
100 fROOTVersion(),
101 fAliROOTVersion(),
102 fUser(),
103 fGridWorkingDir(),
104 fGridDataDir(),
105 fDataPattern(),
106 fGridOutputDir(),
107 fOutputArchive(),
108 fOutputFiles(),
109 fInputFormat(),
e7c71df0 110 fDatasetName(),
c57f56b7 111 fJDLName(),
bb885a9e 112 fMergeExcludes(),
f965131e 113 fIncludePath(),
bb885a9e 114 fCloseSE(),
0df6ccf2 115 fFriendChainName(),
4e5c5506 116 fInputFiles(0),
117 fPackages(0)
c57f56b7 118{
119// Default ctor.
120 SetDefaults();
121}
122
123//______________________________________________________________________________
124AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
125 :AliAnalysisGrid(other),
126 fGridJDL(NULL),
127 fPrice(other.fPrice),
128 fTTL(other.fTTL),
129 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
130 fMaxInitFailed(other.fMaxInitFailed),
131 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
bb885a9e 132 fNtestFiles(other.fNtestFiles),
c57f56b7 133 fRunNumbers(other.fRunNumbers),
134 fExecutable(other.fExecutable),
135 fArguments(other.fArguments),
136 fAnalysisMacro(other.fAnalysisMacro),
137 fAnalysisSource(other.fAnalysisSource),
138 fAdditionalLibs(other.fAdditionalLibs),
139 fSplitMode(other.fSplitMode),
140 fAPIVersion(other.fAPIVersion),
141 fROOTVersion(other.fROOTVersion),
142 fAliROOTVersion(other.fAliROOTVersion),
143 fUser(other.fUser),
144 fGridWorkingDir(other.fGridWorkingDir),
145 fGridDataDir(other.fGridDataDir),
146 fDataPattern(other.fDataPattern),
147 fGridOutputDir(other.fGridOutputDir),
148 fOutputArchive(other.fOutputArchive),
149 fOutputFiles(other.fOutputFiles),
150 fInputFormat(other.fInputFormat),
e7c71df0 151 fDatasetName(other.fDatasetName),
c57f56b7 152 fJDLName(other.fJDLName),
bb885a9e 153 fMergeExcludes(other.fMergeExcludes),
f965131e 154 fIncludePath(other.fIncludePath),
bb885a9e 155 fCloseSE(other.fCloseSE),
0df6ccf2 156 fFriendChainName(other.fFriendChainName),
4e5c5506 157 fInputFiles(0),
158 fPackages(0)
c57f56b7 159{
160// Copy ctor.
161 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
162 if (other.fInputFiles) {
163 fInputFiles = new TObjArray();
164 TIter next(other.fInputFiles);
165 TObject *obj;
166 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
167 fInputFiles->SetOwner();
168 }
4e5c5506 169 if (other.fPackages) {
170 fPackages = new TObjArray();
171 TIter next(other.fPackages);
172 TObject *obj;
173 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
174 fPackages->SetOwner();
175 }
c57f56b7 176}
177
178//______________________________________________________________________________
179AliAnalysisAlien::~AliAnalysisAlien()
180{
181// Destructor.
182 if (fGridJDL) delete fGridJDL;
183 if (fInputFiles) delete fInputFiles;
4e5c5506 184 if (fPackages) delete fPackages;
c57f56b7 185}
186
187//______________________________________________________________________________
188AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
189{
190// Assignment.
191 if (this != &other) {
192 AliAnalysisGrid::operator=(other);
193 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
194 fPrice = other.fPrice;
195 fTTL = other.fTTL;
196 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
197 fMaxInitFailed = other.fMaxInitFailed;
198 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
bb885a9e 199 fNtestFiles = other.fNtestFiles;
c57f56b7 200 fRunNumbers = other.fRunNumbers;
201 fExecutable = other.fExecutable;
202 fArguments = other.fArguments;
203 fAnalysisMacro = other.fAnalysisMacro;
204 fAnalysisSource = other.fAnalysisSource;
205 fAdditionalLibs = other.fAdditionalLibs;
206 fSplitMode = other.fSplitMode;
207 fAPIVersion = other.fAPIVersion;
208 fROOTVersion = other.fROOTVersion;
209 fAliROOTVersion = other.fAliROOTVersion;
210 fUser = other.fUser;
211 fGridWorkingDir = other.fGridWorkingDir;
212 fGridDataDir = other.fGridDataDir;
213 fDataPattern = other.fDataPattern;
214 fGridOutputDir = other.fGridOutputDir;
215 fOutputArchive = other.fOutputArchive;
216 fOutputFiles = other.fOutputFiles;
217 fInputFormat = other.fInputFormat;
e7c71df0 218 fDatasetName = other.fDatasetName;
c57f56b7 219 fJDLName = other.fJDLName;
bb885a9e 220 fMergeExcludes = other.fMergeExcludes;
f965131e 221 fIncludePath = other.fIncludePath;
bb885a9e 222 fCloseSE = other.fCloseSE;
0df6ccf2 223 fFriendChainName = other.fFriendChainName;
c57f56b7 224 if (other.fInputFiles) {
225 fInputFiles = new TObjArray();
226 TIter next(other.fInputFiles);
227 TObject *obj;
228 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
229 fInputFiles->SetOwner();
230 }
4e5c5506 231 if (other.fPackages) {
232 fPackages = new TObjArray();
233 TIter next(other.fPackages);
234 TObject *obj;
235 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
236 fPackages->SetOwner();
237 }
c57f56b7 238 }
239 return *this;
240}
241
242//______________________________________________________________________________
f965131e 243void AliAnalysisAlien::AddIncludePath(const char *path)
244{
245// Add include path in the remote analysis macro.
246 TString p(path);
247 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
248 else fIncludePath += Form("-I%s ", path);
249}
250
251//______________________________________________________________________________
c57f56b7 252void AliAnalysisAlien::AddRunNumber(Int_t run)
253{
254// Add a run number to the list of runs to be processed.
255 if (fRunNumbers.Length()) fRunNumbers += " ";
256 fRunNumbers += Form("%d", run);
257}
258
259//______________________________________________________________________________
260void AliAnalysisAlien::AddDataFile(const char *lfn)
261{
262// Adds a data file to the input to be analysed. The file should be a valid LFN
263// or point to an existing file in the alien workdir.
264 if (!fInputFiles) fInputFiles = new TObjArray();
265 fInputFiles->Add(new TObjString(lfn));
266}
267
268//______________________________________________________________________________
269Bool_t AliAnalysisAlien::Connect()
270{
271// Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
272 if (gGrid && gGrid->IsConnected()) return kTRUE;
273 if (!gSystem->Getenv("alien_API_USER")) {
274 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
275 gSystem->Getenv("UID"));
276 return kFALSE;
277 }
278 if (!gGrid) {
279 Info("Connect", "Trying to connect to AliEn ...");
280 TGrid::Connect("alien://");
281 }
282 if (!gGrid || !gGrid->IsConnected()) {
283 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
284 return kFALSE;
285 }
286 fUser = gGrid->GetUser();
287 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
288 return kTRUE;
289}
290
291//______________________________________________________________________________
292void AliAnalysisAlien::CdWork()
293{
294// Check validity of alien workspace. Create directory if possible.
295 if (!Connect()) {
296 Error("CdWork", "Alien connection required");
297 return;
298 }
299 TString homedir = gGrid->GetHomeDirectory();
300 TString workdir = homedir + fGridWorkingDir;
301 if (!gGrid->Cd(workdir)) {
302 gGrid->Cd(homedir);
303 if (gGrid->Mkdir(workdir)) {
304 gGrid->Cd(fGridWorkingDir);
305 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
306 } else {
307 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
308 workdir.Data(), homedir.Data());
309 fGridWorkingDir = "";
310 }
311 }
312}
313
314//______________________________________________________________________________
315Bool_t AliAnalysisAlien::CheckInputData()
316{
317// Check validity of input data. If necessary, create xml files.
318 if (!fInputFiles && !fRunNumbers.Length()) {
319 Error("CheckInputData", "You have to specify either a set of run numbers or some existing grid files. Use AddRunNumber()/AddDataFile().");
320 return kFALSE;
321 }
322 // Process declared files
323 Bool_t is_collection = kFALSE;
324 Bool_t is_xml = kFALSE;
325 Bool_t use_tags = kFALSE;
326 Bool_t checked = kFALSE;
327 CdWork();
328 TString file;
329 TString workdir = gGrid->GetHomeDirectory();
330 workdir += fGridWorkingDir;
331 if (fInputFiles) {
332 TObjString *objstr;
333 TIter next(fInputFiles);
334 while ((objstr=(TObjString*)next())) {
335 file = workdir;
336 file += "/";
337 file += objstr->GetString();
338 // Store full lfn path
339 if (FileExists(file)) objstr->SetString(file);
340 else {
341 file = objstr->GetName();
342 if (!FileExists(objstr->GetName())) {
343 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
344 objstr->GetName(), workdir.Data());
345 return kFALSE;
346 }
347 }
348 Bool_t iscoll, isxml, usetags;
349 CheckDataType(file, iscoll, isxml, usetags);
350 if (!checked) {
351 checked = kTRUE;
352 is_collection = iscoll;
353 is_xml = isxml;
354 use_tags = usetags;
355 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
356 } else {
357 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
358 Error("CheckInputData", "Some conflict was found in the types of inputs");
359 return kFALSE;
360 }
361 }
362 }
363 }
364 // Process requested run numbers
365 if (!fRunNumbers.Length()) return kTRUE;
366 // Check validity of alien data directory
367 if (!fGridDataDir.Length()) {
368 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
369 return kFALSE;
370 }
371 if (!gGrid->Cd(fGridDataDir)) {
372 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
373 return kFALSE;
374 }
375 if (is_collection) {
376 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
377 return kFALSE;
378 }
379
380 if (checked && !is_xml) {
381 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
382 return kFALSE;
383 }
384 // Check validity of run number(s)
385 TObjArray *arr;
386 TObjString *os;
387 TString path;
388 if (!checked) {
389 checked = kTRUE;
390 use_tags = fDataPattern.Contains("tag");
391 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
392 }
393 if (use_tags != fDataPattern.Contains("tag")) {
394 Error("CheckInputData", "Cannot mix input files using/not using tags");
395 return kFALSE;
396 }
397 if (fRunNumbers.Length()) {
398 arr = fRunNumbers.Tokenize(" ");
399 TIter next(arr);
400 while ((os=(TObjString*)next())) {
401 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
402 if (!gGrid->Cd(path)) {
403 Error("CheckInputData", "Run number %s not found in path: %s", os->GetString().Data(), path.Data());
404 return kFALSE;
405 }
406 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
407 TString msg = "\n##### file: ";
408 msg += path;
409 msg += " type: xml_collection;";
410 if (use_tags) msg += " using_tags: Yes";
411 else msg += " using_tags: No";
412 Info("CheckDataType", msg.Data());
413 AddDataFile(path);
414 }
415 delete arr;
416 }
417 return kTRUE;
418}
419
420//______________________________________________________________________________
421Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
422{
423// Create dataset for the grid data directory + run number.
424 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
425 if (!Connect()) {
426 Error("CreateDataset", "Cannot create dataset with no grid connection");
427 return kFALSE;
428 }
429
430 // Cd workspace
431 CdWork();
432 TString workdir = gGrid->GetHomeDirectory();
433 workdir += fGridWorkingDir;
434
435 // Compose the 'find' command arguments
436 TString command;
437 TString options = "-x collection ";
bb885a9e 438 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
c57f56b7 439 TString conditions = "";
440
441 TString file;
442 TString path;
443 if (!fRunNumbers.Length()) return kTRUE;
444 // Several runs
445 TObjArray *arr = fRunNumbers.Tokenize(" ");
446 TObjString *os;
447 TIter next(arr);
448 while ((os=(TObjString*)next())) {
449 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
1535db97 450 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
451 else file = Form("%s.xml", os->GetString().Data());
452 if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
c57f56b7 453 Info("CreateDataset", "\n##### Removing previous dataset %s", file.Data());
454 gGrid->Rm(file);
455 }
456 command = "find ";
457 command += options;
458 command += path;
459 command += pattern;
1535db97 460// conditions = Form(" > %s", file.Data());
c57f56b7 461 command += conditions;
462 TGridResult *res = gGrid->Command(command);
463 if (res) delete res;
1535db97 464 // Write standard output to file
465 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
466 if (TestBit(AliAnalysisGrid::kTest)) break;
467 // Copy xml file to alien space
468 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
c57f56b7 469 if (!FileExists(file)) {
470 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
471 delete arr;
472 return kFALSE;
473 }
c57f56b7 474 }
475 delete arr;
c57f56b7 476 return kTRUE;
477}
478
479//______________________________________________________________________________
480Bool_t AliAnalysisAlien::CreateJDL()
481{
482// Generate a JDL file according to current settings. The name of the file is
483// specified by fJDLName.
484 Bool_t error = kFALSE;
485 TObjArray *arr = 0;
486 Bool_t copy = kTRUE;
487 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
488 Bool_t generate = kTRUE;
489 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
490 if (!Connect()) {
491 Error("CreateJDL", "Alien connection required");
492 return kFALSE;
493 }
494 // Check validity of alien workspace
495 CdWork();
496 TString workdir = gGrid->GetHomeDirectory();
497 workdir += fGridWorkingDir;
498 if (generate) {
499 TObjString *os;
500 if (!fInputFiles) {
501 Error("CreateJDL()", "Define some input files for your analysis.");
502 error = kTRUE;
503 }
504 // Compose list of input files
505 // Check if output files were defined
506 if (!fOutputFiles.Length()) {
507 Error("CreateJDL", "You must define at least one output file");
508 error = kTRUE;
509 }
510 // Check if an output directory was defined and valid
511 if (!fGridOutputDir.Length()) {
512 Error("CreateJDL", "You must define AliEn output directory");
513 error = kTRUE;
514 } else {
515 if (!gGrid->Cd(fGridOutputDir)) {
516 if (gGrid->Mkdir(fGridOutputDir)) {
517 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
518 } else {
519 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
520 error = kTRUE;
521 }
522 }
523 gGrid->Cd(workdir);
524 }
525 // Exit if any error up to now
526 if (error) return kFALSE;
527 // Set JDL fields
528 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
529 fGridJDL->SetExecutable(fExecutable);
530// fGridJDL->SetTTL((UInt_t)fTTL);
531 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
532 if (fMaxInitFailed > 0)
533 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
534 if (fSplitMaxInputFileNumber > 0)
535 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
536 if (fSplitMode.Length())
537 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
538// fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
539 if (fAliROOTVersion.Length())
540 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
541 if (fROOTVersion.Length())
542 fGridJDL->AddToPackages("ROOT", fROOTVersion);
543 if (fAPIVersion.Length())
544 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
545 fGridJDL->SetInputDataListFormat(fInputFormat);
546 fGridJDL->SetInputDataList("wn.xml");
547 if (fInputFiles) {
548 TIter next(fInputFiles);
549 while ((os=(TObjString*)next()))
550 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
551 }
552 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
553 fGridJDL->AddToInputSandbox(Form("LF:%s/analysis.root", workdir.Data()));
554 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
555 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
556 if (fAdditionalLibs.Length()) {
557 arr = fAdditionalLibs.Tokenize(" ");
558 TIter next(arr);
559 while ((os=(TObjString*)next())) {
560 if (os->GetString().Contains(".so")) continue;
561 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
562 }
563 delete arr;
564 }
4e5c5506 565 if (fPackages) {
566 TIter next(fPackages);
567 TObject *obj;
568 while ((obj=next()))
569 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
570 }
c57f56b7 571 if (fOutputArchive.Length()) {
572 arr = fOutputArchive.Tokenize(" ");
573 TIter next(arr);
574 while ((os=(TObjString*)next()))
43da816a 575 if (!os->GetString().Contains("@") && fCloseSE.Length())
576 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
577 else
578 fGridJDL->AddToOutputArchive(os->GetString());
c57f56b7 579 delete arr;
580 }
581 fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
582 arr = fOutputFiles.Tokenize(" ");
583 TIter next(arr);
43da816a 584 while ((os=(TObjString*)next())) {
585 if (!os->GetString().Contains("@") && fCloseSE.Length())
586 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
587 else
588 fGridJDL->AddToOutputSandbox(os->GetString());
589 }
c57f56b7 590 delete arr;
591// fGridJDL->SetPrice((UInt_t)fPrice);
592 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
593 fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
594 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
595 // Generate the JDL as a string
596 TString sjdl = fGridJDL->Generate();
597 Int_t index;
598 index = sjdl.Index("Executable");
599 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
600 index = sjdl.Index("Split ");
601 if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
602 index = sjdl.Index("SplitMaxInputFileNumber");
603 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
604 index = sjdl.Index("InputDataCollection");
605 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
606 index = sjdl.Index("InputFile");
607 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
608 index = sjdl.Index("InputDataList ");
609 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
610 index = sjdl.Index("InputDataListFormat");
611 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
612 index = sjdl.Index("Price");
613 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
614 index = sjdl.Index("Requirements");
615 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
616 index = sjdl.Index("Packages");
617 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
3b0a0119 618 index = sjdl.Index("User =");
c57f56b7 619 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
620 index = sjdl.Index("TTL");
621 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
622 index = sjdl.Index("OutputFile");
623 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
624 index = sjdl.Index("OutputDir");
625 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
626 index = sjdl.Index("OutputArchive");
627 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
628 index = sjdl.Index("MaxInitFailed");
629 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
630 index = sjdl.Index("MasterResubmitThreshold");
631 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
632 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
633 index = sjdl.Index("Validationcommand");
634 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
635 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
636 sjdl.ReplaceAll("(member", "\n (member");
637 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
638 sjdl.ReplaceAll("{", "{\n ");
639 sjdl.ReplaceAll("};", "\n};");
640 sjdl.ReplaceAll("{\n \n", "{\n");
641 sjdl.ReplaceAll("\n\n", "\n");
642 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
643 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
644 sjdl.Prepend("JobTag = \"Automatically generated analysis JDL\";\n");
645 index = sjdl.Index("JDLVariables");
646 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
647 // Write jdl to file
648 ofstream out;
649 out.open(fJDLName.Data(), ios::out);
650 if (out.bad()) {
651 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
652 return kFALSE;
653 }
654 out << sjdl << endl;
655 }
656 // Copy jdl to grid workspace
657 if (!copy) {
658 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
659 } else {
660 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn working space", fJDLName.Data());
661 if (FileExists(fJDLName)) gGrid->Rm(fJDLName);
662 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s/%s", workdir.Data(), fJDLName.Data()));
663 if (fAdditionalLibs.Length()) {
e7c71df0 664 arr = fAdditionalLibs.Tokenize(" ");
c57f56b7 665 TObjString *os;
666 TIter next(arr);
667 while ((os=(TObjString*)next())) {
c57f56b7 668 if (os->GetString().Contains(".so")) continue;
4e5c5506 669 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
c57f56b7 670 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
671 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
672 }
673 delete arr;
674 }
4e5c5506 675 if (fPackages) {
676 TIter next(fPackages);
677 TObject *obj;
678 while ((obj=next())) {
679 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
680 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
681 }
682 }
c57f56b7 683 }
684 return kTRUE;
685}
686
687//______________________________________________________________________________
688Bool_t AliAnalysisAlien::FileExists(const char *lfn) const
689{
690// Returns true if file exists.
691 if (!gGrid) {
692 Error("FileExists", "No connection to grid");
693 return kFALSE;
694 }
695 TGridResult *res = gGrid->Ls(lfn);
696 if (!res) return kFALSE;
697 TMap *map = dynamic_cast<TMap*>(res->At(0));
698 if (!map) {
699 delete res;
700 return kFALSE;
701 }
702 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
703 if (!objs || !objs->GetString().Length()) {
704 delete res;
705 return kFALSE;
706 }
707 delete res;
708 return kTRUE;
709}
710
711//______________________________________________________________________________
712void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
713{
714// Check input data type.
715 is_collection = kFALSE;
716 is_xml = kFALSE;
717 use_tags = kFALSE;
718 if (!gGrid) {
719 Error("CheckDataType", "No connection to grid");
720 return;
721 }
722 is_collection = IsCollection(lfn);
723 TString msg = "\n##### file: ";
724 msg += lfn;
725 if (is_collection) {
726 msg += " type: raw_collection;";
727 // special treatment for collections
728 is_xml = kFALSE;
729 // check for tag files in the collection
730 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
731 if (!res) {
732 msg += " using_tags: No (unknown)";
733 Info("CheckDataType", msg.Data());
734 return;
735 }
736 const char* typeStr = res->GetKey(0, "origLFN");
737 if (!typeStr || !strlen(typeStr)) {
738 msg += " using_tags: No (unknown)";
739 Info("CheckDataType", msg.Data());
740 return;
741 }
742 TString file = typeStr;
743 use_tags = file.Contains(".tag");
744 if (use_tags) msg += " using_tags: Yes";
745 else msg += " using_tags: No";
746 Info("CheckDataType", msg.Data());
747 return;
748 }
749 TString slfn(lfn);
750 slfn.ToLower();
751 is_xml = slfn.Contains(".xml");
752 if (is_xml) {
753 // Open xml collection and check if there are tag files inside
754 msg += " type: xml_collection;";
755 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
756 if (!coll) {
757 msg += " using_tags: No (unknown)";
758 Info("CheckDataType", msg.Data());
759 return;
760 }
761 TMap *map = coll->Next();
762 if (!map) {
763 msg += " using_tags: No (unknown)";
764 Info("CheckDataType", msg.Data());
765 return;
766 }
767 map = (TMap*)map->GetValue("");
768 TString file;
769 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
770 use_tags = file.Contains(".tag");
771 delete coll;
772 if (use_tags) msg += " using_tags: Yes";
773 else msg += " using_tags: No";
774 Info("CheckDataType", msg.Data());
775 return;
776 }
777 use_tags = slfn.Contains(".tag");
778 if (slfn.Contains(".root")) msg += " type: root file;";
779 else msg += " type: unhnown file;";
780 if (use_tags) msg += " using_tags: Yes";
781 else msg += " using_tags: No";
782 Info("CheckDataType", msg.Data());
783}
784
785//______________________________________________________________________________
4e5c5506 786void AliAnalysisAlien::EnablePackage(const char *package)
787{
788// Enables a par file supposed to exist in the current directory.
789 TString pkg(package);
790 pkg.ReplaceAll(".par", "");
791 pkg += ".par";
792 if (gSystem->AccessPathName(pkg)) {
793 Error("EnablePackage", "Package %s not found", pkg.Data());
794 return;
795 }
796 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
797 Info("EnablePackage", "AliEn plugin will use .par packages");
798 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
799 if (!fPackages) {
800 fPackages = new TObjArray();
801 fPackages->SetOwner();
802 }
803 fPackages->Add(new TObjString(pkg));
804}
805
806//______________________________________________________________________________
c57f56b7 807Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
808{
809// Returns true if file is a collection. Functionality duplicated from
810// TAlien::Type() because we don't want to directly depend on TAlien.
811 if (!gGrid) {
812 Error("IsCollection", "No connection to grid");
813 return kFALSE;
814 }
815 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
816 if (!res) return kFALSE;
817 const char* typeStr = res->GetKey(0, "type");
818 if (!typeStr || !strlen(typeStr)) return kFALSE;
819 if (!strcmp(typeStr, "collection")) return kTRUE;
820 delete res;
821 return kFALSE;
822}
823
824//______________________________________________________________________________
825void AliAnalysisAlien::SetDefaults()
826{
827// Set default values for everything. What cannot be filled will be left empty.
828 if (fGridJDL) delete fGridJDL;
829 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
830 fPrice = 1;
831 fTTL = 30000;
832 fSplitMaxInputFileNumber = 100;
833 fMaxInitFailed = 0;
834 fMasterResubmitThreshold = 0;
bb885a9e 835 fNtestFiles = 10;
c57f56b7 836 fRunNumbers = "";
837 fExecutable = "analysis.sh";
838 fArguments = "";
839 fAnalysisMacro = "myAnalysis.C";
840 fAnalysisSource = "";
841 fAdditionalLibs = "";
842 fSplitMode = "se";
843 fAPIVersion = "";
844 fROOTVersion = "";
845 fAliROOTVersion = "";
846 fUser = ""; // Your alien user name
847 fGridWorkingDir = "";
848 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
849 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
0df6ccf2 850 fFriendChainName = "";
c57f56b7 851 fGridOutputDir = "output";
852 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
853 fOutputFiles = ""; // Like "AliAODs.root histos.root"
854 fInputFormat = "xml-single";
855 fJDLName = "analysis.jdl";
bb885a9e 856 fMergeExcludes = "";
c57f56b7 857}
858
859//______________________________________________________________________________
860Bool_t AliAnalysisAlien::MergeOutputs()
861{
862// Merge analysis outputs existing in the AliEn space.
863 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
864 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
865 if (!Connect()) {
866 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
867 return kFALSE;
868 }
869 // Get the output path
870 TString output = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
871 if (!gGrid->Cd(output)) output = Form("/%s/%s", gGrid->GetHomeDirectory(), fGridOutputDir.Data());
872 if (!gGrid->Cd(output)) {
873 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
874 return kFALSE;
875 }
876 if (!fOutputFiles.Length()) {
877 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
878 return kFALSE;
879 }
880 TObjArray *list = fOutputFiles.Tokenize(" ");
881 TIter next(list);
882 TObjString *str;
883 TString command;
884 TString output_file;
885 Bool_t merged = kTRUE;
886 while((str=(TObjString*)next())) {
887 output_file = str->GetString();
888 Int_t index = output_file.Index("@");
889 if (index > 0) output_file.Remove(index);
bb885a9e 890 if (fMergeExcludes.Length() &&
891 fMergeExcludes.Contains(output_file.Data())) continue;
c57f56b7 892 command = Form("find %s/ *%s", output.Data(), output_file.Data());
893 printf("command: %s\n", command.Data());
894 TGridResult *res = gGrid->Command(command);
895 if (!res) continue;
896 TFileMerger *fm = 0;
897 TIter nextmap(res);
898 TMap *map;
899 while ((map=(TMap*)nextmap())) {
900 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
901 if (!objs || !objs->GetString().Length()) {
902 delete res;
903 continue;
904 }
905 if (!fm) {
906 fm = new TFileMerger(kFALSE);
907 fm->SetFastMethod(kTRUE);
908 fm->OutputFile(output_file);
909 }
910 fm->AddFile(objs->GetString());
911 }
912 if (!fm || !fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
913 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
914 merged = kFALSE;
915 delete res;
916 continue;
917 }
918 if (!fm->Merge()) {
919 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
920 merged = kFALSE;
921 } else {
922 Info("MergeOutputs", "\n##### Merged %d output files <%s>", fm->GetMergeList()->GetSize(), output_file.Data());
923 }
924 delete fm;
925 delete res;
926 }
927 if (!merged) {
928 Error("MergeOutputs", "Terminate() will NOT be executed");
929 }
930 return merged;
931}
932
933//______________________________________________________________________________
bb885a9e 934void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
935{
936// Use the output files connected to output containers from the analysis manager
937// rather than the files defined by SetOutputFiles
938 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
939 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
940 analysis manager");
941 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
942}
943
944//______________________________________________________________________________
c57f56b7 945void AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
946{
947// Start remote grid analysis.
948
43da816a 949 // Check if output files have to be taken from the analysis manager
950 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
951 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
952 if (!mgr || !mgr->IsInitialized()) {
953 Error("StartAnalysis", "You need an initialized analysis manager for this");
954 return;
955 }
956 fOutputFiles = "";
957 TIter next(mgr->GetOutputs());
958 AliAnalysisDataContainer *output;
959 while ((output=(AliAnalysisDataContainer*)next())) {
960 const char *filename = output->GetFileName();
961 if (!(strcmp(filename, "default"))) {
962 if (!mgr->GetOutputEventHandler()) continue;
963 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
964 }
965 if (fOutputFiles.Length()) fOutputFiles += " ";
966 fOutputFiles += filename;
967 }
c07b9ce2 968 // Add extra files registered to the analysis manager
969 if (mgr->GetExtraFiles().Length()) {
970 if (fOutputFiles.Length()) fOutputFiles += " ";
971 fOutputFiles += mgr->GetExtraFiles();
972 }
43da816a 973 }
f7b1cbc2 974// if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
c57f56b7 975 if (TestBit(AliAnalysisGrid::kOffline)) {
976 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
977 \n there nor any job run. You can revise the JDL and analysis \
978 \n macro then run the same in \"submit\" mode.");
979 } else if (TestBit(AliAnalysisGrid::kTest)) {
980 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
981 \n dataset.");
982 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
983 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
984 \n space and job submitted.");
985 } else if (TestBit(AliAnalysisGrid::kMerge)) {
986 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
987 return;
988 } else {
989 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
990 }
991
992 if (!Connect()) {
993 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
994 return;
995 }
996 if (!CheckInputData()) {
997 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
998 return;
999 }
1000 CreateDataset(fDataPattern);
1001 WriteAnalysisFile();
1002 WriteAnalysisMacro();
1003 WriteExecutable();
1004 WriteValidationScript();
1005 if (!CreateJDL()) return;
1006 if (TestBit(AliAnalysisGrid::kOffline)) return;
1007 if (TestBit(AliAnalysisGrid::kTest)) {
1008 // Locally testing the analysis
1009 Info("StartAnalysis", "\n_______________________________________________________________________ \
1010 \n Running analysis script in a daughter shell as on a worker node \
1011 \n_______________________________________________________________________");
1012 TObjArray *list = fOutputFiles.Tokenize(" ");
1013 TIter next(list);
1014 TObjString *str;
1015 TString output_file;
1016 while((str=(TObjString*)next())) {
1017 output_file = str->GetString();
1018 Int_t index = output_file.Index("@");
1019 if (index > 0) output_file.Remove(index);
43da816a 1020 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
c57f56b7 1021 }
1022 delete list;
1023 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1024 gSystem->Exec("bash validate.sh");
1025// gSystem->Exec("cat stdout");
1026 return;
1027 }
1028 // Submit AliEn job
1029 CdWork();
1030 TGridResult *res = gGrid->Command(Form("submit %s", fJDLName.Data()));
0df6ccf2 1031 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
c57f56b7 1032 TString jobID = "";
1033 if (res) {
1034 const char *cjobId = res->GetKey(0,"jobId");
1035 if (!cjobId) {
1036 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1037 return;
1038 } else {
1039 Info("StartAnalysis", "\n_______________________________________________________________________ \
1040 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1041 \n_______________________________________________________________________",
1042 fJDLName.Data(), cjobId);
1043 jobID = cjobId;
1044 }
1045 delete res;
1046 }
1047 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1048 \n You may exit at any time and terminate the job later using the option <terminate> \
1049 \n ##################################################################################", jobID.Data());
bb885a9e 1050 //gGrid->Shell();
1051 gSystem->Exec("aliensh");
c57f56b7 1052}
1053
1054//______________________________________________________________________________
1055void AliAnalysisAlien::WriteAnalysisFile()
1056{
1057// Write current analysis manager into the file analysis.root
1058 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1059 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1060 if (!mgr || !mgr->IsInitialized()) {
1061 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1062 return;
1063 }
1064 // Check analysis type
1065 TObject *handler;
1066 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1067 handler = (TObject*)mgr->GetInputEventHandler();
1068 if (handler) {
1069 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1070 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1071 }
1072 TDirectory *cdir = gDirectory;
1073 TFile *file = TFile::Open("analysis.root", "RECREATE");
1074 if (file) {
1075 mgr->Write();
1076 delete file;
1077 }
1078 if (cdir) cdir->cd();
1079 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1080 }
1081 Bool_t copy = kTRUE;
1082 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1083 if (copy) {
1084 CdWork();
1085 TString workdir = gGrid->GetHomeDirectory();
1086 workdir += fGridWorkingDir;
1087 Info("CreateJDL", "\n##### Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1088 if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1089 TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1090 }
1091}
1092
1093//______________________________________________________________________________
1094void AliAnalysisAlien::WriteAnalysisMacro()
1095{
1096// Write the analysis macro that will steer the analysis in grid mode.
1097 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1098 ofstream out;
1099 out.open(fAnalysisMacro.Data(), ios::out);
1100 if (!out.good()) {
1101 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1102 return;
1103 }
1104 TString func = fAnalysisMacro;
1105 TString type = "ESD";
1106 TString comment = "// Analysis using ";
1107 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1108 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1109 type = "AOD";
1110 comment += "AOD";
1111 }
0df6ccf2 1112 if (type!="AOD" && fFriendChainName!="") {
1113 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1114 return;
1115 }
c57f56b7 1116 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1117 else comment += " data";
1118 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1119 func.ReplaceAll(".C", "");
1120 out << "void " << func.Data() << "()" << endl;
1121 out << "{" << endl;
1122 out << comment.Data() << endl;
1123 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
f7498086 1124 out << " TStopwatch timer;" << endl;
1125 out << " timer.Start();" << endl << endl;
c57f56b7 1126 out << "// load base root libraries" << endl;
1127 out << " gSystem->Load(\"libTree\");" << endl;
1128 out << " gSystem->Load(\"libGeom\");" << endl;
1129 out << " gSystem->Load(\"libVMC\");" << endl;
1130 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
57377eb5 1131 out << "// Load analysis framework libraries" << endl;
4e5c5506 1132 if (!fPackages) {
4e5c5506 1133 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1134 out << " gSystem->Load(\"libESD\");" << endl;
1135 out << " gSystem->Load(\"libAOD\");" << endl;
1136 out << " gSystem->Load(\"libANALYSIS\");" << endl;
57377eb5 1137 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1138 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
4e5c5506 1139 } else {
4e5c5506 1140 TIter next(fPackages);
1141 TObject *obj;
57377eb5 1142 TString pkgname;
1143 Bool_t hasSTEERBase = kFALSE;
1144 Bool_t hasESD = kFALSE;
1145 Bool_t hasAOD = kFALSE;
1146 Bool_t hasANALYSIS = kFALSE;
1147 Bool_t hasANALYSISalice = kFALSE;
1148 Bool_t hasCORRFW = kFALSE;
1149 while ((obj=next())) {
1150 pkgname = obj->GetName();
4478e6f1 1151 if (pkgname == "STEERBase" ||
1152 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1153 if (pkgname == "ESD" ||
1154 pkgname == "ESD.par") hasESD = kTRUE;
1155 if (pkgname == "AOD" ||
1156 pkgname == "AOD.par") hasAOD = kTRUE;
1157 if (pkgname == "ANALYSIS" ||
1158 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1159 if (pkgname == "ANALYSISalice" ||
1160 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1161 if (pkgname == "CORRFW" ||
1162 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
57377eb5 1163 }
1164 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1165 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1166 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1167 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1168 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1169 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1170 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1171 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1172 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1173 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1174 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1175 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1176 out << "// Compile other par packages" << endl;
1177 next.Reset();
fcc9bb6f 1178 while ((obj=next())) {
1179 pkgname = obj->GetName();
4478e6f1 1180 if (pkgname == "STEERBase" ||
1181 pkgname == "STEERBase.par" ||
1182 pkgname == "ESD" ||
1183 pkgname == "ESD.par" ||
1184 pkgname == "AOD" ||
1185 pkgname == "AOD.par" ||
1186 pkgname == "ANALYSIS" ||
1187 pkgname == "ANALYSIS.par" ||
1188 pkgname == "ANALYSISalice" ||
1189 pkgname == "ANALYSISalice.par" ||
1190 pkgname == "CORRFW" ||
1191 pkgname == "CORRFW.par") continue;
4e5c5506 1192 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
fcc9bb6f 1193 }
4e5c5506 1194 }
43da816a 1195 out << "// include path" << endl;
1196 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1197 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
6da75e0b 1198 if (fAdditionalLibs.Length()) {
1199 out << "// Add aditional AliRoot libraries" << endl;
1200 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1201 TIter next(list);
1202 TObjString *str;
1203 while((str=(TObjString*)next())) {
1204 if (str->GetString().Contains(".so"))
1205 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1206 }
1207 if (list) delete list;
1208 }
1209 out << endl;
c57f56b7 1210 out << "// analysis source to be compiled at runtime (if any)" << endl;
1211 if (fAnalysisSource.Length()) {
1212 TObjArray *list = fAnalysisSource.Tokenize(" ");
1213 TIter next(list);
1214 TObjString *str;
1215 while((str=(TObjString*)next())) {
1216 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1217 }
1218 if (list) delete list;
1219 }
1220 out << endl;
1221 out << "// connect to AliEn and make the chain" << endl;
1222 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1223 if (IsUsingTags()) {
1224 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1225 } else {
1226 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1227 }
1228 out << "// read the analysis manager from file" << endl;
1229 out << " TFile *file = TFile::Open(\"analysis.root\");" << endl;
1230 out << " if (!file) return;" << endl;
1231 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1232 out << " AliAnalysisManager *mgr = 0;" << endl;
1233 out << " TKey *key;" << endl;
1234 out << " while ((key=(TKey*)nextkey())) {" << endl;
1235 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1236 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1237 out << " };" << endl;
1238 out << " if (!mgr) {" << endl;
1239 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1240 out << " return;" << endl;
1241 out << " }" << endl << endl;
1242 out << " mgr->PrintStatus();" << endl;
1243 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
f7498086 1244 out << " timer.Stop();" << endl;
1245 out << " timer.Print();" << endl;
c57f56b7 1246 out << "}" << endl << endl;
1247 if (IsUsingTags()) {
1248 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1249 out << "{" << endl;
1250 out << "// Create a chain using tags from the xml file." << endl;
1251 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1252 out << " if (!coll) {" << endl;
1253 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1254 out << " return NULL;" << endl;
1255 out << " }" << endl;
1256 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1257 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1258 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1259 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1260 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1261 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1262 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1263 out << " // Check if the cuts configuration file was provided" << endl;
1264 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1265 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1266 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1267 out << " }" << endl;
0df6ccf2 1268 if (fFriendChainName=="") {
1269 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1270 } else {
1271 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1272 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1273 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1274 }
c57f56b7 1275 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1276 out << " chain->ls();" << endl;
1277 out << " return chain;" << endl;
fcc9bb6f 1278 out << "}" << endl << endl;
c57f56b7 1279 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1280 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1281 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1282 msg += " AliLHCTagCuts *lhcCuts,\n";
1283 msg += " AliDetectorTagCuts *detCuts,\n";
1284 msg += " AliEventTagCuts *evCuts)";
1285 Info("WriteAnalysisMacro", msg.Data());
1286 }
0df6ccf2 1287 }
1288 if (!IsUsingTags() || fFriendChainName!="") {
fcc9bb6f 1289 out <<"//________________________________________________________________________________" << endl;
c57f56b7 1290 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1291 out << "{" << endl;
1292 out << "// Create a chain using url's from xml file" << endl;
1293 out << " TString treename = type;" << endl;
1294 out << " treename.ToLower();" << endl;
1295 out << " treename += \"Tree\";" << endl;
e02fee64 1296 out << " printf(\"***************************************\\n\");" << endl;
1297 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
1298 out << " printf(\"***************************************\\n\");" << endl;
c57f56b7 1299 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1300 out << " if (!coll) {" << endl;
1301 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1302 out << " return NULL;" << endl;
1303 out << " }" << endl;
1304 out << " TChain *chain = new TChain(treename);" << endl;
0df6ccf2 1305 if(fFriendChainName!="") {
1306 out << " TChain *chainFriend = new TChain(treename);" << endl;
1307 }
c57f56b7 1308 out << " coll->Reset();" << endl;
0df6ccf2 1309 out << " while (coll->Next()) {" << endl;
1310 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
1311 if(fFriendChainName!="") {
1312 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
1313 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1314 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1315 out << " chainFriend->Add(fileFriend.Data());" << endl;
1316 }
1317 out << " }" << endl;
c57f56b7 1318 out << " if (!chain->GetNtrees()) {" << endl;
1319 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1320 out << " return NULL;" << endl;
1321 out << " }" << endl;
0df6ccf2 1322 if(fFriendChainName!="") {
1323 out << " chain->AddFriend(chainFriend);" << endl;
1324 }
c57f56b7 1325 out << " return chain;" << endl;
fcc9bb6f 1326 out << "}" << endl << endl;
c57f56b7 1327 }
4e5c5506 1328 if (fPackages) {
fcc9bb6f 1329 out <<"//________________________________________________________________________________" << endl;
4e5c5506 1330 out << "Bool_t SetupPar(const char *package) {" << endl;
1331 out << "// Compile the package and set it up." << endl;
1332 out << " TString pkgdir = package;" << endl;
1333 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
fcc9bb6f 1334 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
4e5c5506 1335 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
1336 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
1337 out << " // Check for BUILD.sh and execute" << endl;
1338 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1339 out << " printf(\"*******************************\\n\");" << endl;
1340 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
1341 out << " printf(\"*******************************\\n\");" << endl;
1342 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
fcc9bb6f 1343 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
4e5c5506 1344 out << " gSystem->ChangeDirectory(cdir);" << endl;
1345 out << " return kFALSE;" << endl;
1346 out << " }" << endl;
1347 out << " } else {" << endl;
fcc9bb6f 1348 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
4e5c5506 1349 out << " gSystem->ChangeDirectory(cdir);" << endl;
1350 out << " return kFALSE;" << endl;
1351 out << " }" << endl;
1352 out << " // Check for SETUP.C and execute" << endl;
1353 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1354 out << " printf(\"*******************************\\n\");" << endl;
1355 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
1356 out << " printf(\"*******************************\\n\");" << endl;
1357 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1358 out << " } else {" << endl;
fcc9bb6f 1359 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
4e5c5506 1360 out << " gSystem->ChangeDirectory(cdir);" << endl;
1361 out << " return kFALSE;" << endl;
1362 out << " }" << endl;
1363 out << " // Restore original workdir" << endl;
1364 out << " gSystem->ChangeDirectory(cdir);" << endl;
1365 out << " return kTRUE;" << endl;
1366 out << "}" << endl;
1367 }
c57f56b7 1368 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1369 }
1370 Bool_t copy = kTRUE;
1371 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1372 if (copy) {
1373 CdWork();
1374 TString workdir = gGrid->GetHomeDirectory();
1375 workdir += fGridWorkingDir;
1376 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1377 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1378 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1379 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1380 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1381 }
1382 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1383 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1384 }
1385}
1386
1387//______________________________________________________________________________
1388void AliAnalysisAlien::WriteExecutable()
1389{
1390// Generate the alien executable script.
1391 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1392 ofstream out;
1393 out.open(fExecutable.Data(), ios::out);
1394 if (out.bad()) {
1395 Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1396 return;
1397 }
1398 out << "#!/bin/bash" << endl;
1399 out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1400 out << "echo \"=========================================\"" << endl;
1401 out << "echo \"############## PATH : ##############\"" << endl;
1402 out << "echo $PATH" << endl;
1403 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1404 out << "echo $LD_LIBRARY_PATH" << endl;
1405 out << "echo \"############## ROOTSYS : ##############\"" << endl;
1406 out << "echo $ROOTSYS" << endl;
1407 out << "echo \"############## which root : ##############\"" << endl;
1408 out << "which root" << endl;
1409 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1410 out << "echo $ALICE_ROOT" << endl;
1411 out << "echo \"############## which aliroot : ##############\"" << endl;
1412 out << "which aliroot" << endl;
1413 out << "echo \"=========================================\"" << endl << endl;
1414// if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1415 out << "root -b -q ";
1416 out << fAnalysisMacro.Data() << endl << endl;
1417 out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1418 }
1419 Bool_t copy = kTRUE;
1420 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1421 if (copy) {
1422 CdWork();
1423 TString workdir = gGrid->GetHomeDirectory();
1424 workdir += fGridWorkingDir;
1425 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1426 if (FileExists(executable)) gGrid->Rm(executable);
1427 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1428 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1429 }
1430}
1431
1432//______________________________________________________________________________
1433void AliAnalysisAlien::WriteValidationScript()
1434{
1435// Generate the alien validation script.
1436 // Generate the validation script
1437 TObjString *os;
1438 if (!Connect()) {
1439 Error("WriteValidationScript", "Alien connection required");
1440 return;
1441 }
1442 TString out_stream = "";
1443 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1444 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1445 ofstream out;
1446 out.open("validate.sh", ios::out);
1447 out << "#!/bin/bash" << endl;
1448 out << "##################################################" << endl;
1449 out << "validateout=`dirname $0`" << endl;
1450 out << "validatetime=`date`" << endl;
1451 out << "validated=\"0\";" << endl;
1452 out << "error=0" << endl;
1453 out << "if [ -z $validateout ]" << endl;
1454 out << "then" << endl;
1455 out << " validateout=\".\"" << endl;
1456 out << "fi" << endl << endl;
1457 out << "cd $validateout;" << endl;
1458 out << "validateworkdir=`pwd`;" << endl << endl;
1459 out << "echo \"*******************************************************\"" << out_stream << endl;
1460 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
1461 out << "" << endl;
1462 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
1463 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
1464 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
1465 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
1466 out << "ls -la ./" << out_stream << endl;
1467 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
1468 out << "##################################################" << endl;
ebec370a 1469
1470 out << "" << endl;
1471 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
1472 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
1473 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
1474 out << "" << endl;
1475
1476 out << "if [ ! -f stderr ] ; then" << endl;
1477 out << " error=1" << endl;
1478 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
1479 out << " echo \"Error = $error\" " << out_stream << endl;
1480 out << "fi" << endl;
1481
1482 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
1483 out << " error=1" << endl;
1484 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
1485 out << " echo \"$parArch\" " << out_stream << endl;
1486 out << " echo \"Error = $error\" " << out_stream << endl;
1487 out << "fi" << endl;
1488
1489 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
1490 out << " error=1" << endl;
1491 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
1492 out << " echo \"$segViol\" " << out_stream << endl;
1493 out << " echo \"Error = $error\" " << out_stream << endl;
1494 out << "fi" << endl;
1495
1496 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
1497 out << " error=1" << endl;
1498 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
1499 out << " echo \"$segFault\" " << out_stream << endl;
1500 out << " echo \"Error = $error\" " << out_stream << endl;
1501 out << "fi" << endl;
1502
1503 // Part dedicated to the specific analyses running into the train
1504
c57f56b7 1505 TObjArray *arr = fOutputFiles.Tokenize(" ");
1506 TIter next1(arr);
1507 TString output_file;
1508 while ((os=(TObjString*)next1())) {
1509 output_file = os->GetString();
1510 Int_t index = output_file.Index("@");
1511 if (index > 0) output_file.Remove(index);
1512 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1513 out << " error=1" << endl;
1514 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
1515 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1516 out << "fi" << endl;
1517 }
1518 delete arr;
1519 out << "if [ $error = 0 ] ; then" << endl;
1520 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
1521 out << "fi" << endl;
1522
1523 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
1524 out << "echo \"*******************************************************\"" << out_stream << endl;
1525 out << "cd -" << endl;
1526 out << "exit $error" << endl;
1527 }
1528 Bool_t copy = kTRUE;
1529 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1530 if (copy) {
1531 CdWork();
1532 TString workdir = gGrid->GetHomeDirectory();
1533 workdir += fGridWorkingDir;
1534 Info("CreateJDL", "\n##### Copying validation script <validate.sh> to your AliEn working space");
1535 if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1536 TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
1537 }
1538}