]> git.uio.no Git - u/mrichter/AliRoot.git/blame - ANALYSIS/AliAnalysisAlien.cxx
New plugin supporting GRID mode for the analysis framework (M.Gheata)
[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"
35#include "AliAnalysisAlien.h"
36
37ClassImp(AliAnalysisAlien)
38
39//______________________________________________________________________________
40AliAnalysisAlien::AliAnalysisAlien()
41 :AliAnalysisGrid(),
42 fGridJDL(NULL),
43 fPrice(0),
44 fTTL(0),
45 fSplitMaxInputFileNumber(0),
46 fMaxInitFailed(0),
47 fMasterResubmitThreshold(0),
48 fRunNumbers(),
49 fExecutable(),
50 fArguments(),
51 fAnalysisMacro(),
52 fAnalysisSource(),
53 fAdditionalLibs(),
54 fSplitMode(),
55 fAPIVersion(),
56 fROOTVersion(),
57 fAliROOTVersion(),
58 fUser(),
59 fGridWorkingDir(),
60 fGridDataDir(),
61 fDataPattern(),
62 fGridOutputDir(),
63 fOutputArchive(),
64 fOutputFiles(),
65 fInputFormat(),
66 fJDLName(),
67 fInputFiles(0)
68{
69// Dummy ctor.
70 SetDefaults();
71}
72
73//______________________________________________________________________________
74AliAnalysisAlien::AliAnalysisAlien(const char *name)
75 :AliAnalysisGrid(name),
76 fGridJDL(NULL),
77 fPrice(0),
78 fTTL(0),
79 fSplitMaxInputFileNumber(0),
80 fMaxInitFailed(0),
81 fMasterResubmitThreshold(0),
82 fRunNumbers(),
83 fExecutable(),
84 fArguments(),
85 fAnalysisMacro(),
86 fAnalysisSource(),
87 fAdditionalLibs(),
88 fSplitMode(),
89 fAPIVersion(),
90 fROOTVersion(),
91 fAliROOTVersion(),
92 fUser(),
93 fGridWorkingDir(),
94 fGridDataDir(),
95 fDataPattern(),
96 fGridOutputDir(),
97 fOutputArchive(),
98 fOutputFiles(),
99 fInputFormat(),
100 fJDLName(),
101 fInputFiles(0)
102{
103// Default ctor.
104 SetDefaults();
105}
106
107//______________________________________________________________________________
108AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
109 :AliAnalysisGrid(other),
110 fGridJDL(NULL),
111 fPrice(other.fPrice),
112 fTTL(other.fTTL),
113 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
114 fMaxInitFailed(other.fMaxInitFailed),
115 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
116 fRunNumbers(other.fRunNumbers),
117 fExecutable(other.fExecutable),
118 fArguments(other.fArguments),
119 fAnalysisMacro(other.fAnalysisMacro),
120 fAnalysisSource(other.fAnalysisSource),
121 fAdditionalLibs(other.fAdditionalLibs),
122 fSplitMode(other.fSplitMode),
123 fAPIVersion(other.fAPIVersion),
124 fROOTVersion(other.fROOTVersion),
125 fAliROOTVersion(other.fAliROOTVersion),
126 fUser(other.fUser),
127 fGridWorkingDir(other.fGridWorkingDir),
128 fGridDataDir(other.fGridDataDir),
129 fDataPattern(other.fDataPattern),
130 fGridOutputDir(other.fGridOutputDir),
131 fOutputArchive(other.fOutputArchive),
132 fOutputFiles(other.fOutputFiles),
133 fInputFormat(other.fInputFormat),
134 fJDLName(other.fJDLName),
135 fInputFiles(0)
136{
137// Copy ctor.
138 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
139 if (other.fInputFiles) {
140 fInputFiles = new TObjArray();
141 TIter next(other.fInputFiles);
142 TObject *obj;
143 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
144 fInputFiles->SetOwner();
145 }
146}
147
148//______________________________________________________________________________
149AliAnalysisAlien::~AliAnalysisAlien()
150{
151// Destructor.
152 if (fGridJDL) delete fGridJDL;
153 if (fInputFiles) delete fInputFiles;
154}
155
156//______________________________________________________________________________
157AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
158{
159// Assignment.
160 if (this != &other) {
161 AliAnalysisGrid::operator=(other);
162 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
163 fPrice = other.fPrice;
164 fTTL = other.fTTL;
165 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
166 fMaxInitFailed = other.fMaxInitFailed;
167 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
168 fRunNumbers = other.fRunNumbers;
169 fExecutable = other.fExecutable;
170 fArguments = other.fArguments;
171 fAnalysisMacro = other.fAnalysisMacro;
172 fAnalysisSource = other.fAnalysisSource;
173 fAdditionalLibs = other.fAdditionalLibs;
174 fSplitMode = other.fSplitMode;
175 fAPIVersion = other.fAPIVersion;
176 fROOTVersion = other.fROOTVersion;
177 fAliROOTVersion = other.fAliROOTVersion;
178 fUser = other.fUser;
179 fGridWorkingDir = other.fGridWorkingDir;
180 fGridDataDir = other.fGridDataDir;
181 fDataPattern = other.fDataPattern;
182 fGridOutputDir = other.fGridOutputDir;
183 fOutputArchive = other.fOutputArchive;
184 fOutputFiles = other.fOutputFiles;
185 fInputFormat = other.fInputFormat;
186 fJDLName = other.fJDLName;
187 if (other.fInputFiles) {
188 fInputFiles = new TObjArray();
189 TIter next(other.fInputFiles);
190 TObject *obj;
191 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
192 fInputFiles->SetOwner();
193 }
194 }
195 return *this;
196}
197
198//______________________________________________________________________________
199void AliAnalysisAlien::AddRunNumber(Int_t run)
200{
201// Add a run number to the list of runs to be processed.
202 if (fRunNumbers.Length()) fRunNumbers += " ";
203 fRunNumbers += Form("%d", run);
204}
205
206//______________________________________________________________________________
207void AliAnalysisAlien::AddDataFile(const char *lfn)
208{
209// Adds a data file to the input to be analysed. The file should be a valid LFN
210// or point to an existing file in the alien workdir.
211 if (!fInputFiles) fInputFiles = new TObjArray();
212 fInputFiles->Add(new TObjString(lfn));
213}
214
215//______________________________________________________________________________
216Bool_t AliAnalysisAlien::Connect()
217{
218// Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
219 if (gGrid && gGrid->IsConnected()) return kTRUE;
220 if (!gSystem->Getenv("alien_API_USER")) {
221 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
222 gSystem->Getenv("UID"));
223 return kFALSE;
224 }
225 if (!gGrid) {
226 Info("Connect", "Trying to connect to AliEn ...");
227 TGrid::Connect("alien://");
228 }
229 if (!gGrid || !gGrid->IsConnected()) {
230 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
231 return kFALSE;
232 }
233 fUser = gGrid->GetUser();
234 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
235 return kTRUE;
236}
237
238//______________________________________________________________________________
239void AliAnalysisAlien::CdWork()
240{
241// Check validity of alien workspace. Create directory if possible.
242 if (!Connect()) {
243 Error("CdWork", "Alien connection required");
244 return;
245 }
246 TString homedir = gGrid->GetHomeDirectory();
247 TString workdir = homedir + fGridWorkingDir;
248 if (!gGrid->Cd(workdir)) {
249 gGrid->Cd(homedir);
250 if (gGrid->Mkdir(workdir)) {
251 gGrid->Cd(fGridWorkingDir);
252 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
253 } else {
254 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
255 workdir.Data(), homedir.Data());
256 fGridWorkingDir = "";
257 }
258 }
259}
260
261//______________________________________________________________________________
262Bool_t AliAnalysisAlien::CheckInputData()
263{
264// Check validity of input data. If necessary, create xml files.
265 if (!fInputFiles && !fRunNumbers.Length()) {
266 Error("CheckInputData", "You have to specify either a set of run numbers or some existing grid files. Use AddRunNumber()/AddDataFile().");
267 return kFALSE;
268 }
269 // Process declared files
270 Bool_t is_collection = kFALSE;
271 Bool_t is_xml = kFALSE;
272 Bool_t use_tags = kFALSE;
273 Bool_t checked = kFALSE;
274 CdWork();
275 TString file;
276 TString workdir = gGrid->GetHomeDirectory();
277 workdir += fGridWorkingDir;
278 if (fInputFiles) {
279 TObjString *objstr;
280 TIter next(fInputFiles);
281 while ((objstr=(TObjString*)next())) {
282 file = workdir;
283 file += "/";
284 file += objstr->GetString();
285 // Store full lfn path
286 if (FileExists(file)) objstr->SetString(file);
287 else {
288 file = objstr->GetName();
289 if (!FileExists(objstr->GetName())) {
290 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
291 objstr->GetName(), workdir.Data());
292 return kFALSE;
293 }
294 }
295 Bool_t iscoll, isxml, usetags;
296 CheckDataType(file, iscoll, isxml, usetags);
297 if (!checked) {
298 checked = kTRUE;
299 is_collection = iscoll;
300 is_xml = isxml;
301 use_tags = usetags;
302 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
303 } else {
304 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
305 Error("CheckInputData", "Some conflict was found in the types of inputs");
306 return kFALSE;
307 }
308 }
309 }
310 }
311 // Process requested run numbers
312 if (!fRunNumbers.Length()) return kTRUE;
313 // Check validity of alien data directory
314 if (!fGridDataDir.Length()) {
315 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
316 return kFALSE;
317 }
318 if (!gGrid->Cd(fGridDataDir)) {
319 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
320 return kFALSE;
321 }
322 if (is_collection) {
323 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
324 return kFALSE;
325 }
326
327 if (checked && !is_xml) {
328 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
329 return kFALSE;
330 }
331 // Check validity of run number(s)
332 TObjArray *arr;
333 TObjString *os;
334 TString path;
335 if (!checked) {
336 checked = kTRUE;
337 use_tags = fDataPattern.Contains("tag");
338 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
339 }
340 if (use_tags != fDataPattern.Contains("tag")) {
341 Error("CheckInputData", "Cannot mix input files using/not using tags");
342 return kFALSE;
343 }
344 if (fRunNumbers.Length()) {
345 arr = fRunNumbers.Tokenize(" ");
346 TIter next(arr);
347 while ((os=(TObjString*)next())) {
348 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
349 if (!gGrid->Cd(path)) {
350 Error("CheckInputData", "Run number %s not found in path: %s", os->GetString().Data(), path.Data());
351 return kFALSE;
352 }
353 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
354 TString msg = "\n##### file: ";
355 msg += path;
356 msg += " type: xml_collection;";
357 if (use_tags) msg += " using_tags: Yes";
358 else msg += " using_tags: No";
359 Info("CheckDataType", msg.Data());
360 AddDataFile(path);
361 }
362 delete arr;
363 }
364 return kTRUE;
365}
366
367//______________________________________________________________________________
368Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
369{
370// Create dataset for the grid data directory + run number.
371 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
372 if (!Connect()) {
373 Error("CreateDataset", "Cannot create dataset with no grid connection");
374 return kFALSE;
375 }
376
377 // Cd workspace
378 CdWork();
379 TString workdir = gGrid->GetHomeDirectory();
380 workdir += fGridWorkingDir;
381
382 // Compose the 'find' command arguments
383 TString command;
384 TString options = "-x collection ";
385 if (TestBit(AliAnalysisGrid::kTest)) options += "-l 10 ";
386 TString conditions = "";
387
388 TString file;
389 TString path;
390 if (!fRunNumbers.Length()) return kTRUE;
391 // Several runs
392 TObjArray *arr = fRunNumbers.Tokenize(" ");
393 TObjString *os;
394 TIter next(arr);
395 while ((os=(TObjString*)next())) {
396 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
397 file = Form("%s.xml", os->GetString().Data());
398 if (FileExists(file)) {
399 Info("CreateDataset", "\n##### Removing previous dataset %s", file.Data());
400 gGrid->Rm(file);
401 }
402 command = "find ";
403 command += options;
404 command += path;
405 command += pattern;
406 conditions = Form(" > %s", file.Data());
407 command += conditions;
408 TGridResult *res = gGrid->Command(command);
409 if (res) delete res;
410 if (!FileExists(file)) {
411 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
412 delete arr;
413 return kFALSE;
414 }
415 if (TestBit(AliAnalysisGrid::kTest)) break;
416 }
417 delete arr;
418 // Copy the file back to client if local testing is requested.
419 if (TestBit(AliAnalysisGrid::kTest)) {
420 Info("CreateDataset", "\n##### Copying dataset <%s> to <wn.xml> in your current directory...", file.Data());
421 TFile::Cp(Form("alien://%s/%s", workdir.Data(), file.Data()), "file:wn.xml",file.Data());
422 }
423 return kTRUE;
424}
425
426//______________________________________________________________________________
427Bool_t AliAnalysisAlien::CreateJDL()
428{
429// Generate a JDL file according to current settings. The name of the file is
430// specified by fJDLName.
431 Bool_t error = kFALSE;
432 TObjArray *arr = 0;
433 Bool_t copy = kTRUE;
434 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
435 Bool_t generate = kTRUE;
436 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
437 if (!Connect()) {
438 Error("CreateJDL", "Alien connection required");
439 return kFALSE;
440 }
441 // Check validity of alien workspace
442 CdWork();
443 TString workdir = gGrid->GetHomeDirectory();
444 workdir += fGridWorkingDir;
445 if (generate) {
446 TObjString *os;
447 if (!fInputFiles) {
448 Error("CreateJDL()", "Define some input files for your analysis.");
449 error = kTRUE;
450 }
451 // Compose list of input files
452 // Check if output files were defined
453 if (!fOutputFiles.Length()) {
454 Error("CreateJDL", "You must define at least one output file");
455 error = kTRUE;
456 }
457 // Check if an output directory was defined and valid
458 if (!fGridOutputDir.Length()) {
459 Error("CreateJDL", "You must define AliEn output directory");
460 error = kTRUE;
461 } else {
462 if (!gGrid->Cd(fGridOutputDir)) {
463 if (gGrid->Mkdir(fGridOutputDir)) {
464 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
465 } else {
466 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
467 error = kTRUE;
468 }
469 }
470 gGrid->Cd(workdir);
471 }
472 // Exit if any error up to now
473 if (error) return kFALSE;
474 // Set JDL fields
475 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
476 fGridJDL->SetExecutable(fExecutable);
477// fGridJDL->SetTTL((UInt_t)fTTL);
478 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
479 if (fMaxInitFailed > 0)
480 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
481 if (fSplitMaxInputFileNumber > 0)
482 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
483 if (fSplitMode.Length())
484 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
485// fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
486 if (fAliROOTVersion.Length())
487 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
488 if (fROOTVersion.Length())
489 fGridJDL->AddToPackages("ROOT", fROOTVersion);
490 if (fAPIVersion.Length())
491 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
492 fGridJDL->SetInputDataListFormat(fInputFormat);
493 fGridJDL->SetInputDataList("wn.xml");
494 if (fInputFiles) {
495 TIter next(fInputFiles);
496 while ((os=(TObjString*)next()))
497 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
498 }
499 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
500 fGridJDL->AddToInputSandbox(Form("LF:%s/analysis.root", workdir.Data()));
501 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
502 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
503 if (fAdditionalLibs.Length()) {
504 arr = fAdditionalLibs.Tokenize(" ");
505 TIter next(arr);
506 while ((os=(TObjString*)next())) {
507 if (os->GetString().Contains(".so")) continue;
508 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
509 }
510 delete arr;
511 }
512 if (fOutputArchive.Length()) {
513 arr = fOutputArchive.Tokenize(" ");
514 TIter next(arr);
515 while ((os=(TObjString*)next()))
516 fGridJDL->AddToOutputArchive(os->GetString().Data());
517 delete arr;
518 }
519 fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
520 arr = fOutputFiles.Tokenize(" ");
521 TIter next(arr);
522 while ((os=(TObjString*)next())) fGridJDL->AddToOutputSandbox(os->GetString());
523 delete arr;
524// fGridJDL->SetPrice((UInt_t)fPrice);
525 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
526 fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
527 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
528 // Generate the JDL as a string
529 TString sjdl = fGridJDL->Generate();
530 Int_t index;
531 index = sjdl.Index("Executable");
532 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
533 index = sjdl.Index("Split ");
534 if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
535 index = sjdl.Index("SplitMaxInputFileNumber");
536 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
537 index = sjdl.Index("InputDataCollection");
538 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
539 index = sjdl.Index("InputFile");
540 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
541 index = sjdl.Index("InputDataList ");
542 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
543 index = sjdl.Index("InputDataListFormat");
544 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
545 index = sjdl.Index("Price");
546 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
547 index = sjdl.Index("Requirements");
548 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
549 index = sjdl.Index("Packages");
550 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
551 index = sjdl.Index("User");
552 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
553 index = sjdl.Index("TTL");
554 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
555 index = sjdl.Index("OutputFile");
556 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
557 index = sjdl.Index("OutputDir");
558 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
559 index = sjdl.Index("OutputArchive");
560 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
561 index = sjdl.Index("MaxInitFailed");
562 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
563 index = sjdl.Index("MasterResubmitThreshold");
564 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
565 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
566 index = sjdl.Index("Validationcommand");
567 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
568 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
569 sjdl.ReplaceAll("(member", "\n (member");
570 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
571 sjdl.ReplaceAll("{", "{\n ");
572 sjdl.ReplaceAll("};", "\n};");
573 sjdl.ReplaceAll("{\n \n", "{\n");
574 sjdl.ReplaceAll("\n\n", "\n");
575 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
576 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
577 sjdl.Prepend("JobTag = \"Automatically generated analysis JDL\";\n");
578 index = sjdl.Index("JDLVariables");
579 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
580 // Write jdl to file
581 ofstream out;
582 out.open(fJDLName.Data(), ios::out);
583 if (out.bad()) {
584 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
585 return kFALSE;
586 }
587 out << sjdl << endl;
588 }
589 // Copy jdl to grid workspace
590 if (!copy) {
591 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
592 } else {
593 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn working space", fJDLName.Data());
594 if (FileExists(fJDLName)) gGrid->Rm(fJDLName);
595 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s/%s", workdir.Data(), fJDLName.Data()));
596 if (fAdditionalLibs.Length()) {
597 TObjArray *arr = fAdditionalLibs.Tokenize(" ");
598 TObjString *os;
599 TIter next(arr);
600 while ((os=(TObjString*)next())) {
601 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
602 if (os->GetString().Contains(".so")) continue;
603 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
604 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
605 }
606 delete arr;
607 }
608 }
609 return kTRUE;
610}
611
612//______________________________________________________________________________
613Bool_t AliAnalysisAlien::FileExists(const char *lfn) const
614{
615// Returns true if file exists.
616 if (!gGrid) {
617 Error("FileExists", "No connection to grid");
618 return kFALSE;
619 }
620 TGridResult *res = gGrid->Ls(lfn);
621 if (!res) return kFALSE;
622 TMap *map = dynamic_cast<TMap*>(res->At(0));
623 if (!map) {
624 delete res;
625 return kFALSE;
626 }
627 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
628 if (!objs || !objs->GetString().Length()) {
629 delete res;
630 return kFALSE;
631 }
632 delete res;
633 return kTRUE;
634}
635
636//______________________________________________________________________________
637void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
638{
639// Check input data type.
640 is_collection = kFALSE;
641 is_xml = kFALSE;
642 use_tags = kFALSE;
643 if (!gGrid) {
644 Error("CheckDataType", "No connection to grid");
645 return;
646 }
647 is_collection = IsCollection(lfn);
648 TString msg = "\n##### file: ";
649 msg += lfn;
650 if (is_collection) {
651 msg += " type: raw_collection;";
652 // special treatment for collections
653 is_xml = kFALSE;
654 // check for tag files in the collection
655 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
656 if (!res) {
657 msg += " using_tags: No (unknown)";
658 Info("CheckDataType", msg.Data());
659 return;
660 }
661 const char* typeStr = res->GetKey(0, "origLFN");
662 if (!typeStr || !strlen(typeStr)) {
663 msg += " using_tags: No (unknown)";
664 Info("CheckDataType", msg.Data());
665 return;
666 }
667 TString file = typeStr;
668 use_tags = file.Contains(".tag");
669 if (use_tags) msg += " using_tags: Yes";
670 else msg += " using_tags: No";
671 Info("CheckDataType", msg.Data());
672 return;
673 }
674 TString slfn(lfn);
675 slfn.ToLower();
676 is_xml = slfn.Contains(".xml");
677 if (is_xml) {
678 // Open xml collection and check if there are tag files inside
679 msg += " type: xml_collection;";
680 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
681 if (!coll) {
682 msg += " using_tags: No (unknown)";
683 Info("CheckDataType", msg.Data());
684 return;
685 }
686 TMap *map = coll->Next();
687 if (!map) {
688 msg += " using_tags: No (unknown)";
689 Info("CheckDataType", msg.Data());
690 return;
691 }
692 map = (TMap*)map->GetValue("");
693 TString file;
694 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
695 use_tags = file.Contains(".tag");
696 delete coll;
697 if (use_tags) msg += " using_tags: Yes";
698 else msg += " using_tags: No";
699 Info("CheckDataType", msg.Data());
700 return;
701 }
702 use_tags = slfn.Contains(".tag");
703 if (slfn.Contains(".root")) msg += " type: root file;";
704 else msg += " type: unhnown file;";
705 if (use_tags) msg += " using_tags: Yes";
706 else msg += " using_tags: No";
707 Info("CheckDataType", msg.Data());
708}
709
710//______________________________________________________________________________
711Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
712{
713// Returns true if file is a collection. Functionality duplicated from
714// TAlien::Type() because we don't want to directly depend on TAlien.
715 if (!gGrid) {
716 Error("IsCollection", "No connection to grid");
717 return kFALSE;
718 }
719 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
720 if (!res) return kFALSE;
721 const char* typeStr = res->GetKey(0, "type");
722 if (!typeStr || !strlen(typeStr)) return kFALSE;
723 if (!strcmp(typeStr, "collection")) return kTRUE;
724 delete res;
725 return kFALSE;
726}
727
728//______________________________________________________________________________
729void AliAnalysisAlien::SetDefaults()
730{
731// Set default values for everything. What cannot be filled will be left empty.
732 if (fGridJDL) delete fGridJDL;
733 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
734 fPrice = 1;
735 fTTL = 30000;
736 fSplitMaxInputFileNumber = 100;
737 fMaxInitFailed = 0;
738 fMasterResubmitThreshold = 0;
739 fRunNumbers = "";
740 fExecutable = "analysis.sh";
741 fArguments = "";
742 fAnalysisMacro = "myAnalysis.C";
743 fAnalysisSource = "";
744 fAdditionalLibs = "";
745 fSplitMode = "se";
746 fAPIVersion = "";
747 fROOTVersion = "";
748 fAliROOTVersion = "";
749 fUser = ""; // Your alien user name
750 fGridWorkingDir = "";
751 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
752 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
753 fGridOutputDir = "output";
754 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
755 fOutputFiles = ""; // Like "AliAODs.root histos.root"
756 fInputFormat = "xml-single";
757 fJDLName = "analysis.jdl";
758}
759
760//______________________________________________________________________________
761Bool_t AliAnalysisAlien::MergeOutputs()
762{
763// Merge analysis outputs existing in the AliEn space.
764 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
765 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
766 if (!Connect()) {
767 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
768 return kFALSE;
769 }
770 // Get the output path
771 TString output = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
772 if (!gGrid->Cd(output)) output = Form("/%s/%s", gGrid->GetHomeDirectory(), fGridOutputDir.Data());
773 if (!gGrid->Cd(output)) {
774 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
775 return kFALSE;
776 }
777 if (!fOutputFiles.Length()) {
778 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
779 return kFALSE;
780 }
781 TObjArray *list = fOutputFiles.Tokenize(" ");
782 TIter next(list);
783 TObjString *str;
784 TString command;
785 TString output_file;
786 Bool_t merged = kTRUE;
787 while((str=(TObjString*)next())) {
788 output_file = str->GetString();
789 Int_t index = output_file.Index("@");
790 if (index > 0) output_file.Remove(index);
791 command = Form("find %s/ *%s", output.Data(), output_file.Data());
792 printf("command: %s\n", command.Data());
793 TGridResult *res = gGrid->Command(command);
794 if (!res) continue;
795 TFileMerger *fm = 0;
796 TIter nextmap(res);
797 TMap *map;
798 while ((map=(TMap*)nextmap())) {
799 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
800 if (!objs || !objs->GetString().Length()) {
801 delete res;
802 continue;
803 }
804 if (!fm) {
805 fm = new TFileMerger(kFALSE);
806 fm->SetFastMethod(kTRUE);
807 fm->OutputFile(output_file);
808 }
809 fm->AddFile(objs->GetString());
810 }
811 if (!fm || !fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
812 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
813 merged = kFALSE;
814 delete res;
815 continue;
816 }
817 if (!fm->Merge()) {
818 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
819 merged = kFALSE;
820 } else {
821 Info("MergeOutputs", "\n##### Merged %d output files <%s>", fm->GetMergeList()->GetSize(), output_file.Data());
822 }
823 delete fm;
824 delete res;
825 }
826 if (!merged) {
827 Error("MergeOutputs", "Terminate() will NOT be executed");
828 }
829 return merged;
830}
831
832//______________________________________________________________________________
833void AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
834{
835// Start remote grid analysis.
836
837 if (TestBit(AliAnalysisGrid::kOffline)) {
838 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
839 \n there nor any job run. You can revise the JDL and analysis \
840 \n macro then run the same in \"submit\" mode.");
841 } else if (TestBit(AliAnalysisGrid::kTest)) {
842 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
843 \n dataset.");
844 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
845 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
846 \n space and job submitted.");
847 } else if (TestBit(AliAnalysisGrid::kMerge)) {
848 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
849 return;
850 } else {
851 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
852 }
853
854 if (!Connect()) {
855 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
856 return;
857 }
858 if (!CheckInputData()) {
859 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
860 return;
861 }
862 CreateDataset(fDataPattern);
863 WriteAnalysisFile();
864 WriteAnalysisMacro();
865 WriteExecutable();
866 WriteValidationScript();
867 if (!CreateJDL()) return;
868 if (TestBit(AliAnalysisGrid::kOffline)) return;
869 if (TestBit(AliAnalysisGrid::kTest)) {
870 // Locally testing the analysis
871 Info("StartAnalysis", "\n_______________________________________________________________________ \
872 \n Running analysis script in a daughter shell as on a worker node \
873 \n_______________________________________________________________________");
874 TObjArray *list = fOutputFiles.Tokenize(" ");
875 TIter next(list);
876 TObjString *str;
877 TString output_file;
878 while((str=(TObjString*)next())) {
879 output_file = str->GetString();
880 Int_t index = output_file.Index("@");
881 if (index > 0) output_file.Remove(index);
882 gSystem->Exec(Form("rm %s", output_file.Data()));
883 }
884 delete list;
885 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
886 gSystem->Exec("bash validate.sh");
887// gSystem->Exec("cat stdout");
888 return;
889 }
890 // Submit AliEn job
891 CdWork();
892 TGridResult *res = gGrid->Command(Form("submit %s", fJDLName.Data()));
893 TString jobID = "";
894 if (res) {
895 const char *cjobId = res->GetKey(0,"jobId");
896 if (!cjobId) {
897 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
898 return;
899 } else {
900 Info("StartAnalysis", "\n_______________________________________________________________________ \
901 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
902 \n_______________________________________________________________________",
903 fJDLName.Data(), cjobId);
904 jobID = cjobId;
905 }
906 delete res;
907 }
908 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
909 \n You may exit at any time and terminate the job later using the option <terminate> \
910 \n ##################################################################################", jobID.Data());
911 gGrid->Shell();
912}
913
914//______________________________________________________________________________
915void AliAnalysisAlien::WriteAnalysisFile()
916{
917// Write current analysis manager into the file analysis.root
918 if (!TestBit(AliAnalysisGrid::kSubmit)) {
919 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
920 if (!mgr || !mgr->IsInitialized()) {
921 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
922 return;
923 }
924 // Check analysis type
925 TObject *handler;
926 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
927 handler = (TObject*)mgr->GetInputEventHandler();
928 if (handler) {
929 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
930 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
931 }
932 TDirectory *cdir = gDirectory;
933 TFile *file = TFile::Open("analysis.root", "RECREATE");
934 if (file) {
935 mgr->Write();
936 delete file;
937 }
938 if (cdir) cdir->cd();
939 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
940 }
941 Bool_t copy = kTRUE;
942 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
943 if (copy) {
944 CdWork();
945 TString workdir = gGrid->GetHomeDirectory();
946 workdir += fGridWorkingDir;
947 Info("CreateJDL", "\n##### Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
948 if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
949 TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
950 }
951}
952
953//______________________________________________________________________________
954void AliAnalysisAlien::WriteAnalysisMacro()
955{
956// Write the analysis macro that will steer the analysis in grid mode.
957 if (!TestBit(AliAnalysisGrid::kSubmit)) {
958 ofstream out;
959 out.open(fAnalysisMacro.Data(), ios::out);
960 if (!out.good()) {
961 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
962 return;
963 }
964 TString func = fAnalysisMacro;
965 TString type = "ESD";
966 TString comment = "// Analysis using ";
967 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
968 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
969 type = "AOD";
970 comment += "AOD";
971 }
972 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
973 else comment += " data";
974 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
975 func.ReplaceAll(".C", "");
976 out << "void " << func.Data() << "()" << endl;
977 out << "{" << endl;
978 out << comment.Data() << endl;
979 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
980 out << "// load base root libraries" << endl;
981 out << " gSystem->Load(\"libTree\");" << endl;
982 out << " gSystem->Load(\"libGeom\");" << endl;
983 out << " gSystem->Load(\"libVMC\");" << endl;
984 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
985 out << "// load analysis framework libraries" << endl;
986 out << " gSystem->Load(\"libSTEERBase\");" << endl;
987 out << " gSystem->Load(\"libESD\");" << endl;
988 out << " gSystem->Load(\"libAOD\");" << endl;
989 out << " gSystem->Load(\"libANALYSIS\");" << endl;
990 out << " gSystem->Load(\"libANALYSISalice\");" << endl << endl;
991 out << "// add aditional AliRoot libraries below" << endl;
992 if (fAdditionalLibs.Length()) {
993 TObjArray *list = fAdditionalLibs.Tokenize(" ");
994 TIter next(list);
995 TObjString *str;
996 while((str=(TObjString*)next())) {
997 if (str->GetString().Contains(".so"))
998 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
999 }
1000 if (list) delete list;
1001 }
1002 out << endl;
1003 out << "// include path (remove if using par files)" << endl;
1004 out << " gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl << endl;
1005 out << "// analysis source to be compiled at runtime (if any)" << endl;
1006 if (fAnalysisSource.Length()) {
1007 TObjArray *list = fAnalysisSource.Tokenize(" ");
1008 TIter next(list);
1009 TObjString *str;
1010 while((str=(TObjString*)next())) {
1011 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1012 }
1013 if (list) delete list;
1014 }
1015 out << endl;
1016 out << "// connect to AliEn and make the chain" << endl;
1017 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1018 if (IsUsingTags()) {
1019 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1020 } else {
1021 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1022 }
1023 out << "// read the analysis manager from file" << endl;
1024 out << " TFile *file = TFile::Open(\"analysis.root\");" << endl;
1025 out << " if (!file) return;" << endl;
1026 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1027 out << " AliAnalysisManager *mgr = 0;" << endl;
1028 out << " TKey *key;" << endl;
1029 out << " while ((key=(TKey*)nextkey())) {" << endl;
1030 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1031 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1032 out << " };" << endl;
1033 out << " if (!mgr) {" << endl;
1034 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1035 out << " return;" << endl;
1036 out << " }" << endl << endl;
1037 out << " mgr->PrintStatus();" << endl;
1038 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1039 out << "}" << endl << endl;
1040 if (IsUsingTags()) {
1041 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1042 out << "{" << endl;
1043 out << "// Create a chain using tags from the xml file." << endl;
1044 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1045 out << " if (!coll) {" << endl;
1046 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1047 out << " return NULL;" << endl;
1048 out << " }" << endl;
1049 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1050 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1051 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1052 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1053 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1054 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1055 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1056 out << " // Check if the cuts configuration file was provided" << endl;
1057 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1058 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1059 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1060 out << " }" << endl;
1061 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1062 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1063 out << " chain->ls();" << endl;
1064 out << " return chain;" << endl;
1065 out << "}" << endl;
1066 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1067 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1068 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1069 msg += " AliLHCTagCuts *lhcCuts,\n";
1070 msg += " AliDetectorTagCuts *detCuts,\n";
1071 msg += " AliEventTagCuts *evCuts)";
1072 Info("WriteAnalysisMacro", msg.Data());
1073 }
1074 } else {
1075 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1076 out << "{" << endl;
1077 out << "// Create a chain using url's from xml file" << endl;
1078 out << " TString treename = type;" << endl;
1079 out << " treename.ToLower();" << endl;
1080 out << " treename += \"Tree\";" << endl;
1081 out << " printf(\"***************************************\");" << endl;
1082 out << " printf(\" Getting chain of trees %s\\n\", treename);" << endl;
1083 out << " printf(\"***************************************\");" << endl;
1084 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1085 out << " if (!coll) {" << endl;
1086 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1087 out << " return NULL;" << endl;
1088 out << " }" << endl;
1089 out << " TChain *chain = new TChain(treename);" << endl;
1090 out << " coll->Reset();" << endl;
1091 out << " while (coll->Next()) chain->Add(coll->GetTURL(\"\"));" << endl;
1092 out << " if (!chain->GetNtrees()) {" << endl;
1093 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1094 out << " return NULL;" << endl;
1095 out << " }" << endl;
1096 out << " return chain;" << endl;
1097 out << "}" << endl;
1098 }
1099 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1100 }
1101 Bool_t copy = kTRUE;
1102 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1103 if (copy) {
1104 CdWork();
1105 TString workdir = gGrid->GetHomeDirectory();
1106 workdir += fGridWorkingDir;
1107 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1108 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1109 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1110 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1111 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1112 }
1113 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1114 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1115 }
1116}
1117
1118//______________________________________________________________________________
1119void AliAnalysisAlien::WriteExecutable()
1120{
1121// Generate the alien executable script.
1122 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1123 ofstream out;
1124 out.open(fExecutable.Data(), ios::out);
1125 if (out.bad()) {
1126 Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1127 return;
1128 }
1129 out << "#!/bin/bash" << endl;
1130 out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1131 out << "echo \"=========================================\"" << endl;
1132 out << "echo \"############## PATH : ##############\"" << endl;
1133 out << "echo $PATH" << endl;
1134 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1135 out << "echo $LD_LIBRARY_PATH" << endl;
1136 out << "echo \"############## ROOTSYS : ##############\"" << endl;
1137 out << "echo $ROOTSYS" << endl;
1138 out << "echo \"############## which root : ##############\"" << endl;
1139 out << "which root" << endl;
1140 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1141 out << "echo $ALICE_ROOT" << endl;
1142 out << "echo \"############## which aliroot : ##############\"" << endl;
1143 out << "which aliroot" << endl;
1144 out << "echo \"=========================================\"" << endl << endl;
1145// if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1146 out << "root -b -q ";
1147 out << fAnalysisMacro.Data() << endl << endl;
1148 out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1149 }
1150 Bool_t copy = kTRUE;
1151 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1152 if (copy) {
1153 CdWork();
1154 TString workdir = gGrid->GetHomeDirectory();
1155 workdir += fGridWorkingDir;
1156 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1157 if (FileExists(executable)) gGrid->Rm(executable);
1158 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1159 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1160 }
1161}
1162
1163//______________________________________________________________________________
1164void AliAnalysisAlien::WriteValidationScript()
1165{
1166// Generate the alien validation script.
1167 // Generate the validation script
1168 TObjString *os;
1169 if (!Connect()) {
1170 Error("WriteValidationScript", "Alien connection required");
1171 return;
1172 }
1173 TString out_stream = "";
1174 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1175 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1176 ofstream out;
1177 out.open("validate.sh", ios::out);
1178 out << "#!/bin/bash" << endl;
1179 out << "##################################################" << endl;
1180 out << "validateout=`dirname $0`" << endl;
1181 out << "validatetime=`date`" << endl;
1182 out << "validated=\"0\";" << endl;
1183 out << "error=0" << endl;
1184 out << "if [ -z $validateout ]" << endl;
1185 out << "then" << endl;
1186 out << " validateout=\".\"" << endl;
1187 out << "fi" << endl << endl;
1188 out << "cd $validateout;" << endl;
1189 out << "validateworkdir=`pwd`;" << endl << endl;
1190 out << "echo \"*******************************************************\"" << out_stream << endl;
1191 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
1192 out << "" << endl;
1193 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
1194 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
1195 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
1196 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
1197 out << "ls -la ./" << out_stream << endl;
1198 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
1199 out << "##################################################" << endl;
1200 TObjArray *arr = fOutputFiles.Tokenize(" ");
1201 TIter next1(arr);
1202 TString output_file;
1203 while ((os=(TObjString*)next1())) {
1204 output_file = os->GetString();
1205 Int_t index = output_file.Index("@");
1206 if (index > 0) output_file.Remove(index);
1207 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1208 out << " error=1" << endl;
1209 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
1210 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1211 out << "fi" << endl;
1212 }
1213 delete arr;
1214 out << "if [ $error = 0 ] ; then" << endl;
1215 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
1216 out << "fi" << endl;
1217
1218 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
1219 out << "echo \"*******************************************************\"" << out_stream << endl;
1220 out << "cd -" << endl;
1221 out << "exit $error" << endl;
1222 }
1223 Bool_t copy = kTRUE;
1224 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1225 if (copy) {
1226 CdWork();
1227 TString workdir = gGrid->GetHomeDirectory();
1228 workdir += fGridWorkingDir;
1229 Info("CreateJDL", "\n##### Copying validation script <validate.sh> to your AliEn working space");
1230 if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1231 TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
1232 }
1233}