1 /**************************************************************************
2 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
16 // Author: Mihaela Gheata, 01/09/2008
18 //==============================================================================
19 // AliAnalysisAlien - AliEn utility class. Provides interface for creating
20 // a personalized JDL, finding and creating a dataset.
21 //==============================================================================
23 #include "Riostream.h"
27 #include "TObjString.h"
28 #include "TObjArray.h"
30 #include "TGridResult.h"
31 #include "TGridCollection.h"
33 #include "TFileMerger.h"
34 #include "AliAnalysisManager.h"
35 #include "AliVEventHandler.h"
36 #include "AliAnalysisDataContainer.h"
37 #include "AliAnalysisAlien.h"
39 ClassImp(AliAnalysisAlien)
41 //______________________________________________________________________________
42 AliAnalysisAlien::AliAnalysisAlien()
47 fSplitMaxInputFileNumber(0),
49 fMasterResubmitThreshold(0),
83 //______________________________________________________________________________
84 AliAnalysisAlien::AliAnalysisAlien(const char *name)
85 :AliAnalysisGrid(name),
89 fSplitMaxInputFileNumber(0),
91 fMasterResubmitThreshold(0),
125 //______________________________________________________________________________
126 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
127 :AliAnalysisGrid(other),
129 fPrice(other.fPrice),
131 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
132 fMaxInitFailed(other.fMaxInitFailed),
133 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
134 fNtestFiles(other.fNtestFiles),
135 fNMasterJobs(other.fNMasterJobs),
136 fRunNumbers(other.fRunNumbers),
137 fExecutable(other.fExecutable),
138 fArguments(other.fArguments),
139 fAnalysisMacro(other.fAnalysisMacro),
140 fAnalysisSource(other.fAnalysisSource),
141 fAdditionalLibs(other.fAdditionalLibs),
142 fSplitMode(other.fSplitMode),
143 fAPIVersion(other.fAPIVersion),
144 fROOTVersion(other.fROOTVersion),
145 fAliROOTVersion(other.fAliROOTVersion),
147 fGridWorkingDir(other.fGridWorkingDir),
148 fGridDataDir(other.fGridDataDir),
149 fDataPattern(other.fDataPattern),
150 fGridOutputDir(other.fGridOutputDir),
151 fOutputArchive(other.fOutputArchive),
152 fOutputFiles(other.fOutputFiles),
153 fInputFormat(other.fInputFormat),
154 fDatasetName(other.fDatasetName),
155 fJDLName(other.fJDLName),
156 fMergeExcludes(other.fMergeExcludes),
157 fIncludePath(other.fIncludePath),
158 fCloseSE(other.fCloseSE),
159 fFriendChainName(other.fFriendChainName),
164 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
165 fRunRange[0] = other.fRunRange[0];
166 fRunRange[1] = other.fRunRange[1];
167 if (other.fInputFiles) {
168 fInputFiles = new TObjArray();
169 TIter next(other.fInputFiles);
171 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
172 fInputFiles->SetOwner();
174 if (other.fPackages) {
175 fPackages = new TObjArray();
176 TIter next(other.fPackages);
178 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
179 fPackages->SetOwner();
183 //______________________________________________________________________________
184 AliAnalysisAlien::~AliAnalysisAlien()
187 if (fGridJDL) delete fGridJDL;
188 if (fInputFiles) delete fInputFiles;
189 if (fPackages) delete fPackages;
192 //______________________________________________________________________________
193 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
196 if (this != &other) {
197 AliAnalysisGrid::operator=(other);
198 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
199 fPrice = other.fPrice;
201 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
202 fMaxInitFailed = other.fMaxInitFailed;
203 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
204 fNtestFiles = other.fNtestFiles;
205 fRunNumbers = other.fRunNumbers;
206 fExecutable = other.fExecutable;
207 fArguments = other.fArguments;
208 fAnalysisMacro = other.fAnalysisMacro;
209 fAnalysisSource = other.fAnalysisSource;
210 fAdditionalLibs = other.fAdditionalLibs;
211 fSplitMode = other.fSplitMode;
212 fAPIVersion = other.fAPIVersion;
213 fROOTVersion = other.fROOTVersion;
214 fAliROOTVersion = other.fAliROOTVersion;
216 fGridWorkingDir = other.fGridWorkingDir;
217 fGridDataDir = other.fGridDataDir;
218 fDataPattern = other.fDataPattern;
219 fGridOutputDir = other.fGridOutputDir;
220 fOutputArchive = other.fOutputArchive;
221 fOutputFiles = other.fOutputFiles;
222 fInputFormat = other.fInputFormat;
223 fDatasetName = other.fDatasetName;
224 fJDLName = other.fJDLName;
225 fMergeExcludes = other.fMergeExcludes;
226 fIncludePath = other.fIncludePath;
227 fCloseSE = other.fCloseSE;
228 fFriendChainName = other.fFriendChainName;
229 if (other.fInputFiles) {
230 fInputFiles = new TObjArray();
231 TIter next(other.fInputFiles);
233 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
234 fInputFiles->SetOwner();
236 if (other.fPackages) {
237 fPackages = new TObjArray();
238 TIter next(other.fPackages);
240 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
241 fPackages->SetOwner();
247 //______________________________________________________________________________
248 void AliAnalysisAlien::AddIncludePath(const char *path)
250 // Add include path in the remote analysis macro.
252 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
253 else fIncludePath += Form("-I%s ", path);
256 //______________________________________________________________________________
257 void AliAnalysisAlien::AddRunNumber(Int_t run)
259 // Add a run number to the list of runs to be processed.
260 if (fRunNumbers.Length()) fRunNumbers += " ";
261 fRunNumbers += Form("%d", run);
264 //______________________________________________________________________________
265 void AliAnalysisAlien::AddDataFile(const char *lfn)
267 // Adds a data file to the input to be analysed. The file should be a valid LFN
268 // or point to an existing file in the alien workdir.
269 if (!fInputFiles) fInputFiles = new TObjArray();
270 fInputFiles->Add(new TObjString(lfn));
273 //______________________________________________________________________________
274 Bool_t AliAnalysisAlien::Connect()
276 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
277 if (gGrid && gGrid->IsConnected()) return kTRUE;
278 if (!gSystem->Getenv("alien_API_USER")) {
279 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
280 gSystem->Getenv("UID"));
284 Info("Connect", "Trying to connect to AliEn ...");
285 TGrid::Connect("alien://");
287 if (!gGrid || !gGrid->IsConnected()) {
288 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
291 fUser = gGrid->GetUser();
292 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
296 //______________________________________________________________________________
297 void AliAnalysisAlien::CdWork()
299 // Check validity of alien workspace. Create directory if possible.
301 Error("CdWork", "Alien connection required");
304 TString homedir = gGrid->GetHomeDirectory();
305 TString workdir = homedir + fGridWorkingDir;
306 if (!gGrid->Cd(workdir)) {
308 if (gGrid->Mkdir(workdir)) {
309 gGrid->Cd(fGridWorkingDir);
310 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
312 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
313 workdir.Data(), homedir.Data());
314 fGridWorkingDir = "";
319 //______________________________________________________________________________
320 Bool_t AliAnalysisAlien::CheckInputData()
322 // Check validity of input data. If necessary, create xml files.
323 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
324 Error("CheckInputData", "You have to specify either a set of run numbers or some existing grid files. Use AddRunNumber()/AddDataFile()/SetRunRange().");
327 // Process declared files
328 Bool_t is_collection = kFALSE;
329 Bool_t is_xml = kFALSE;
330 Bool_t use_tags = kFALSE;
331 Bool_t checked = kFALSE;
334 TString workdir = gGrid->GetHomeDirectory();
335 workdir += fGridWorkingDir;
338 TIter next(fInputFiles);
339 while ((objstr=(TObjString*)next())) {
342 file += objstr->GetString();
343 // Store full lfn path
344 if (FileExists(file)) objstr->SetString(file);
346 file = objstr->GetName();
347 if (!FileExists(objstr->GetName())) {
348 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
349 objstr->GetName(), workdir.Data());
353 Bool_t iscoll, isxml, usetags;
354 CheckDataType(file, iscoll, isxml, usetags);
357 is_collection = iscoll;
360 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
362 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
363 Error("CheckInputData", "Some conflict was found in the types of inputs");
369 // Process requested run numbers
370 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
371 // Check validity of alien data directory
372 if (!fGridDataDir.Length()) {
373 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
376 if (!gGrid->Cd(fGridDataDir)) {
377 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
381 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
385 if (checked && !is_xml) {
386 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
389 // Check validity of run number(s)
395 use_tags = fDataPattern.Contains("tag");
396 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
398 if (use_tags != fDataPattern.Contains("tag")) {
399 Error("CheckInputData", "Cannot mix input files using/not using tags");
402 if (fRunNumbers.Length()) {
403 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
404 arr = fRunNumbers.Tokenize(" ");
406 while ((os=(TObjString*)next())) {
407 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
408 if (!gGrid->Cd(path)) {
409 Warning("CheckInputData", "Run number %s not found in path: %s", os->GetString().Data(), path.Data());
412 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
413 TString msg = "\n##### file: ";
415 msg += " type: xml_collection;";
416 if (use_tags) msg += " using_tags: Yes";
417 else msg += " using_tags: No";
418 Info("CheckDataType", msg.Data());
423 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
424 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
425 path = Form("%s/%d ", fGridDataDir.Data(), irun);
426 if (!gGrid->Cd(path)) {
427 Warning("CheckInputData", "Run number %d not found in path: %s", irun, path.Data());
430 path = Form("%s/%d.xml", workdir.Data(),irun);
431 TString msg = "\n##### file: ";
433 msg += " type: xml_collection;";
434 if (use_tags) msg += " using_tags: Yes";
435 else msg += " using_tags: No";
436 Info("CheckDataType", msg.Data());
443 //______________________________________________________________________________
444 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
446 // Create dataset for the grid data directory + run number.
447 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
449 Error("CreateDataset", "Cannot create dataset with no grid connection");
455 TString workdir = gGrid->GetHomeDirectory();
456 workdir += fGridWorkingDir;
458 // Compose the 'find' command arguments
460 TString options = "-x collection ";
461 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
462 TString conditions = "";
466 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
468 if (fRunNumbers.Length()) {
469 TObjArray *arr = fRunNumbers.Tokenize(" ");
472 while ((os=(TObjString*)next())) {
473 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
474 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
475 else file = Form("%s.xml", os->GetString().Data());
476 if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
477 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
485 // conditions = Form(" > %s", file.Data());
486 command += conditions;
487 TGridResult *res = gGrid->Command(command);
489 // Write standard output to file
490 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
491 if (TestBit(AliAnalysisGrid::kTest)) break;
492 // Copy xml file to alien space
493 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
494 if (!FileExists(file)) {
495 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
502 // Process a full run range.
503 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
504 path = Form("%s/%d ", fGridDataDir.Data(), irun);
505 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
506 else file = Form("%d.xml", irun);
507 if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
508 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
516 // conditions = Form(" > %s", file.Data());
517 command += conditions;
518 TGridResult *res = gGrid->Command(command);
520 // Write standard output to file
521 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
522 if (TestBit(AliAnalysisGrid::kTest)) break;
523 // Copy xml file to alien space
524 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
525 if (!FileExists(file)) {
526 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
534 //______________________________________________________________________________
535 Bool_t AliAnalysisAlien::CreateJDL()
537 // Generate a JDL file according to current settings. The name of the file is
538 // specified by fJDLName.
539 Bool_t error = kFALSE;
542 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
543 Bool_t generate = kTRUE;
544 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
546 Error("CreateJDL", "Alien connection required");
549 // Check validity of alien workspace
551 TString workdir = gGrid->GetHomeDirectory();
552 workdir += fGridWorkingDir;
556 Error("CreateJDL()", "Define some input files for your analysis.");
559 // Compose list of input files
560 // Check if output files were defined
561 if (!fOutputFiles.Length()) {
562 Error("CreateJDL", "You must define at least one output file");
565 // Check if an output directory was defined and valid
566 if (!fGridOutputDir.Length()) {
567 Error("CreateJDL", "You must define AliEn output directory");
570 if (!gGrid->Cd(fGridOutputDir)) {
571 if (gGrid->Mkdir(fGridOutputDir)) {
572 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
574 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
580 // Exit if any error up to now
581 if (error) return kFALSE;
583 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
584 fGridJDL->SetExecutable(fExecutable);
585 // fGridJDL->SetTTL((UInt_t)fTTL);
586 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
587 if (fMaxInitFailed > 0)
588 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
589 if (fSplitMaxInputFileNumber > 0)
590 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
591 if (fSplitMode.Length())
592 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
593 // fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
594 if (fAliROOTVersion.Length())
595 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
596 if (fROOTVersion.Length())
597 fGridJDL->AddToPackages("ROOT", fROOTVersion);
598 if (fAPIVersion.Length())
599 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
600 fGridJDL->SetInputDataListFormat(fInputFormat);
601 fGridJDL->SetInputDataList("wn.xml");
602 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
603 fGridJDL->AddToInputSandbox(Form("LF:%s/analysis.root", workdir.Data()));
604 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
605 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
606 if (fAdditionalLibs.Length()) {
607 arr = fAdditionalLibs.Tokenize(" ");
609 while ((os=(TObjString*)next())) {
610 if (os->GetString().Contains(".so")) continue;
611 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
616 TIter next(fPackages);
619 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
621 if (fOutputArchive.Length()) {
622 arr = fOutputArchive.Tokenize(" ");
624 while ((os=(TObjString*)next()))
625 if (!os->GetString().Contains("@") && fCloseSE.Length())
626 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
628 fGridJDL->AddToOutputArchive(os->GetString());
631 arr = fOutputFiles.Tokenize(" ");
633 while ((os=(TObjString*)next())) {
634 if (!os->GetString().Contains("@") && fCloseSE.Length())
635 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
637 fGridJDL->AddToOutputSandbox(os->GetString());
640 // fGridJDL->SetPrice((UInt_t)fPrice);
641 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
642 fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
643 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
644 // Depending if going through a run range or not, generate one or mode jdl's
645 if (!fRunRange[0]) WriteJDL(-1,copy);
647 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++)
648 WriteJDL(irun-fRunRange[0],copy);
651 // Copy jdl to grid workspace
653 if (fAdditionalLibs.Length()) {
654 arr = fAdditionalLibs.Tokenize(" ");
657 while ((os=(TObjString*)next())) {
658 if (os->GetString().Contains(".so")) continue;
659 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
660 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
661 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
666 TIter next(fPackages);
668 while ((obj=next())) {
669 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
670 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
677 //______________________________________________________________________________
678 Bool_t AliAnalysisAlien::WriteJDL(Int_t findex, Bool_t copy)
680 // Writes one or more JDL's corresponding to findex. If findex is negative,
681 // all run numbers are considered in one go (jdl). For non-negative indices
682 // they correspond to the indices in the array fInputFiles.
683 if (!fInputFiles) return kFALSE;
686 TString workdir = gGrid->GetHomeDirectory();
687 workdir += fGridWorkingDir;
690 TIter next(fInputFiles);
691 while ((os=(TObjString*)next()))
692 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
693 fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
695 os = (TObjString*)fInputFiles->At(findex);
696 line = "#Input xml collection\n";
697 line += "InputDataCollection = {";
698 line += Form(" \"LF:%s,nodownload\"", os->GetString().Data());
700 fGridJDL->SetOutputDirectory(Form("%s/%s/%03d#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data(),findex));
704 // Generate the JDL as a string
705 TString sjdl = fGridJDL->Generate();
707 index = sjdl.Index("Executable");
708 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
709 index = sjdl.Index("Split ");
710 if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
711 index = sjdl.Index("SplitMaxInputFileNumber");
712 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
713 index = sjdl.Index("InputDataCollection");
714 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
716 index = sjdl.Index("OutputDir");
717 sjdl.Insert(index, line.Data());
719 index = sjdl.Index("InputFile");
720 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
721 index = sjdl.Index("InputDataList ");
722 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
723 index = sjdl.Index("InputDataListFormat");
724 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
725 index = sjdl.Index("Price");
726 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
727 index = sjdl.Index("Requirements");
728 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
729 index = sjdl.Index("Packages");
730 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
731 index = sjdl.Index("User =");
732 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
733 index = sjdl.Index("TTL");
734 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
735 index = sjdl.Index("OutputFile");
736 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
737 index = sjdl.Index("OutputDir");
738 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
739 index = sjdl.Index("OutputArchive");
740 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
741 index = sjdl.Index("MaxInitFailed");
742 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
743 index = sjdl.Index("MasterResubmitThreshold");
744 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
745 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
746 index = sjdl.Index("Validationcommand");
747 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
748 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
749 sjdl.ReplaceAll("(member", "\n (member");
750 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
751 sjdl.ReplaceAll("{", "{\n ");
752 sjdl.ReplaceAll("};", "\n};");
753 sjdl.ReplaceAll("{\n \n", "{\n");
754 sjdl.ReplaceAll("\n\n", "\n");
755 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
756 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
757 sjdl.Prepend("JobTag = \"Automatically generated analysis JDL\";\n");
758 index = sjdl.Index("JDLVariables");
759 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
761 TString snjdl = fJDLName;
762 if (findex >=0) snjdl.ReplaceAll(".jdl", Form("_%03d.jdl", findex));
764 out.open(snjdl.Data(), ios::out);
766 Error("CreateJDL", "Bad file name: %s", snjdl.Data());
771 // Copy jdl to grid workspace
773 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
775 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn working space", snjdl.Data());
776 if (FileExists(snjdl)) gGrid->Rm(snjdl);
777 TFile::Cp(Form("file:%s",snjdl.Data()), Form("alien://%s/%s", workdir.Data(), snjdl.Data()));
782 //______________________________________________________________________________
783 Bool_t AliAnalysisAlien::FileExists(const char *lfn) const
785 // Returns true if file exists.
787 Error("FileExists", "No connection to grid");
790 TGridResult *res = gGrid->Ls(lfn);
791 if (!res) return kFALSE;
792 TMap *map = dynamic_cast<TMap*>(res->At(0));
797 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
798 if (!objs || !objs->GetString().Length()) {
806 //______________________________________________________________________________
807 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
809 // Check input data type.
810 is_collection = kFALSE;
814 Error("CheckDataType", "No connection to grid");
817 is_collection = IsCollection(lfn);
818 TString msg = "\n##### file: ";
821 msg += " type: raw_collection;";
822 // special treatment for collections
824 // check for tag files in the collection
825 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
827 msg += " using_tags: No (unknown)";
828 Info("CheckDataType", msg.Data());
831 const char* typeStr = res->GetKey(0, "origLFN");
832 if (!typeStr || !strlen(typeStr)) {
833 msg += " using_tags: No (unknown)";
834 Info("CheckDataType", msg.Data());
837 TString file = typeStr;
838 use_tags = file.Contains(".tag");
839 if (use_tags) msg += " using_tags: Yes";
840 else msg += " using_tags: No";
841 Info("CheckDataType", msg.Data());
846 is_xml = slfn.Contains(".xml");
848 // Open xml collection and check if there are tag files inside
849 msg += " type: xml_collection;";
850 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
852 msg += " using_tags: No (unknown)";
853 Info("CheckDataType", msg.Data());
856 TMap *map = coll->Next();
858 msg += " using_tags: No (unknown)";
859 Info("CheckDataType", msg.Data());
862 map = (TMap*)map->GetValue("");
864 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
865 use_tags = file.Contains(".tag");
867 if (use_tags) msg += " using_tags: Yes";
868 else msg += " using_tags: No";
869 Info("CheckDataType", msg.Data());
872 use_tags = slfn.Contains(".tag");
873 if (slfn.Contains(".root")) msg += " type: root file;";
874 else msg += " type: unhnown file;";
875 if (use_tags) msg += " using_tags: Yes";
876 else msg += " using_tags: No";
877 Info("CheckDataType", msg.Data());
880 //______________________________________________________________________________
881 void AliAnalysisAlien::EnablePackage(const char *package)
883 // Enables a par file supposed to exist in the current directory.
884 TString pkg(package);
885 pkg.ReplaceAll(".par", "");
887 if (gSystem->AccessPathName(pkg)) {
888 Error("EnablePackage", "Package %s not found", pkg.Data());
891 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
892 Info("EnablePackage", "AliEn plugin will use .par packages");
893 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
895 fPackages = new TObjArray();
896 fPackages->SetOwner();
898 fPackages->Add(new TObjString(pkg));
901 //______________________________________________________________________________
902 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
904 // Returns true if file is a collection. Functionality duplicated from
905 // TAlien::Type() because we don't want to directly depend on TAlien.
907 Error("IsCollection", "No connection to grid");
910 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
911 if (!res) return kFALSE;
912 const char* typeStr = res->GetKey(0, "type");
913 if (!typeStr || !strlen(typeStr)) return kFALSE;
914 if (!strcmp(typeStr, "collection")) return kTRUE;
919 //______________________________________________________________________________
920 void AliAnalysisAlien::SetDefaults()
922 // Set default values for everything. What cannot be filled will be left empty.
923 if (fGridJDL) delete fGridJDL;
924 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
927 fSplitMaxInputFileNumber = 100;
929 fMasterResubmitThreshold = 0;
935 fExecutable = "analysis.sh";
937 fAnalysisMacro = "myAnalysis.C";
938 fAnalysisSource = "";
939 fAdditionalLibs = "";
943 fAliROOTVersion = "";
944 fUser = ""; // Your alien user name
945 fGridWorkingDir = "";
946 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
947 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
948 fFriendChainName = "";
949 fGridOutputDir = "output";
950 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
951 fOutputFiles = ""; // Like "AliAODs.root histos.root"
952 fInputFormat = "xml-single";
953 fJDLName = "analysis.jdl";
957 //______________________________________________________________________________
958 Bool_t AliAnalysisAlien::MergeOutputs()
960 // Merge analysis outputs existing in the AliEn space.
961 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
962 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
964 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
967 // Get the output path
968 TString output = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
969 if (!gGrid->Cd(output)) output = Form("/%s/%s", gGrid->GetHomeDirectory(), fGridOutputDir.Data());
970 if (!gGrid->Cd(output)) {
971 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
974 if (!fOutputFiles.Length()) {
975 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
978 TObjArray *list = fOutputFiles.Tokenize(" ");
983 Bool_t merged = kTRUE;
984 while((str=(TObjString*)next())) {
985 output_file = str->GetString();
986 Int_t index = output_file.Index("@");
987 if (index > 0) output_file.Remove(index);
988 if (fMergeExcludes.Length() &&
989 fMergeExcludes.Contains(output_file.Data())) continue;
990 command = Form("find %s/ *%s", output.Data(), output_file.Data());
991 printf("command: %s\n", command.Data());
992 TGridResult *res = gGrid->Command(command);
997 while ((map=(TMap*)nextmap())) {
998 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
999 if (!objs || !objs->GetString().Length()) {
1004 fm = new TFileMerger(kFALSE);
1005 fm->SetFastMethod(kTRUE);
1006 fm->OutputFile(output_file);
1008 fm->AddFile(objs->GetString());
1010 if (!fm || !fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1011 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1017 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1020 Info("MergeOutputs", "\n##### Merged %d output files <%s>", fm->GetMergeList()->GetSize(), output_file.Data());
1026 Error("MergeOutputs", "Terminate() will NOT be executed");
1031 //______________________________________________________________________________
1032 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1034 // Use the output files connected to output containers from the analysis manager
1035 // rather than the files defined by SetOutputFiles
1036 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1037 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1039 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1042 //______________________________________________________________________________
1043 void AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1045 // Start remote grid analysis.
1047 // Check if output files have to be taken from the analysis manager
1048 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1049 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1050 if (!mgr || !mgr->IsInitialized()) {
1051 Error("StartAnalysis", "You need an initialized analysis manager for this");
1055 TIter next(mgr->GetOutputs());
1056 AliAnalysisDataContainer *output;
1057 while ((output=(AliAnalysisDataContainer*)next())) {
1058 const char *filename = output->GetFileName();
1059 if (!(strcmp(filename, "default"))) {
1060 if (!mgr->GetOutputEventHandler()) continue;
1061 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1063 if (fOutputFiles.Length()) fOutputFiles += " ";
1064 fOutputFiles += filename;
1066 // Add extra files registered to the analysis manager
1067 if (mgr->GetExtraFiles().Length()) {
1068 if (fOutputFiles.Length()) fOutputFiles += " ";
1069 fOutputFiles += mgr->GetExtraFiles();
1072 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1073 if (TestBit(AliAnalysisGrid::kOffline)) {
1074 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1075 \n there nor any job run. You can revise the JDL and analysis \
1076 \n macro then run the same in \"submit\" mode.");
1077 } else if (TestBit(AliAnalysisGrid::kTest)) {
1078 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1080 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1081 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1082 \n space and job submitted.");
1083 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1084 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1087 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1091 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1094 if (!CheckInputData()) {
1095 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1098 CreateDataset(fDataPattern);
1099 WriteAnalysisFile();
1100 WriteAnalysisMacro();
1102 WriteValidationScript();
1103 if (!CreateJDL()) return;
1104 if (TestBit(AliAnalysisGrid::kOffline)) return;
1105 if (TestBit(AliAnalysisGrid::kTest)) {
1106 // Locally testing the analysis
1107 Info("StartAnalysis", "\n_______________________________________________________________________ \
1108 \n Running analysis script in a daughter shell as on a worker node \
1109 \n_______________________________________________________________________");
1110 TObjArray *list = fOutputFiles.Tokenize(" ");
1113 TString output_file;
1114 while((str=(TObjString*)next())) {
1115 output_file = str->GetString();
1116 Int_t index = output_file.Index("@");
1117 if (index > 0) output_file.Remove(index);
1118 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1121 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1122 gSystem->Exec("bash validate.sh");
1123 // gSystem->Exec("cat stdout");
1126 // Submit AliEn job(s)
1130 if (fRunNumbers.Length()) {
1131 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1132 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1134 const char *cjobId = res->GetKey(0,"jobId");
1136 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1139 Info("StartAnalysis", "\n_______________________________________________________________________ \
1140 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1141 \n_______________________________________________________________________",
1142 fJDLName.Data(), cjobId);
1148 if (!fRunRange[0]) {
1149 Error("StartAnalysis", "No runs defined. Exiting.");
1153 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1155 sjdl.ReplaceAll(".jdl", Form("_%03d.jdl", irun-fRunRange[0]));
1156 res = gGrid->Command(Form("submit %s", sjdl.Data()));
1157 printf("*************************** %s\n",Form("submit %s", sjdl.Data()));
1159 const char *cjobId1 = res->GetKey(0,"jobId");
1161 Error("StartAnalysis", "Your JDL %s could not be submitted", sjdl.Data());
1164 Info("StartAnalysis", "\n_______________________________________________________________________ \
1165 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1166 \n_______________________________________________________________________",
1167 sjdl.Data(), cjobId1);
1176 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1177 \n You may exit at any time and terminate the job later using the option <terminate> \
1178 \n ##################################################################################", jobID.Data());
1180 gSystem->Exec("aliensh");
1183 //______________________________________________________________________________
1184 void AliAnalysisAlien::WriteAnalysisFile()
1186 // Write current analysis manager into the file analysis.root
1187 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1188 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1189 if (!mgr || !mgr->IsInitialized()) {
1190 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1193 // Check analysis type
1195 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1196 handler = (TObject*)mgr->GetInputEventHandler();
1198 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1199 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1201 TDirectory *cdir = gDirectory;
1202 TFile *file = TFile::Open("analysis.root", "RECREATE");
1207 if (cdir) cdir->cd();
1208 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1210 Bool_t copy = kTRUE;
1211 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1214 TString workdir = gGrid->GetHomeDirectory();
1215 workdir += fGridWorkingDir;
1216 Info("CreateJDL", "\n##### Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1217 if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1218 TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1222 //______________________________________________________________________________
1223 void AliAnalysisAlien::WriteAnalysisMacro()
1225 // Write the analysis macro that will steer the analysis in grid mode.
1226 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1228 out.open(fAnalysisMacro.Data(), ios::out);
1230 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1233 TString func = fAnalysisMacro;
1234 TString type = "ESD";
1235 TString comment = "// Analysis using ";
1236 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1237 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1241 if (type!="AOD" && fFriendChainName!="") {
1242 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1245 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1246 else comment += " data";
1247 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1248 func.ReplaceAll(".C", "");
1249 out << "void " << func.Data() << "()" << endl;
1251 out << comment.Data() << endl;
1252 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1253 out << " TStopwatch timer;" << endl;
1254 out << " timer.Start();" << endl << endl;
1255 out << "// load base root libraries" << endl;
1256 out << " gSystem->Load(\"libTree\");" << endl;
1257 out << " gSystem->Load(\"libGeom\");" << endl;
1258 out << " gSystem->Load(\"libVMC\");" << endl;
1259 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
1260 out << "// Load analysis framework libraries" << endl;
1262 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1263 out << " gSystem->Load(\"libESD\");" << endl;
1264 out << " gSystem->Load(\"libAOD\");" << endl;
1265 out << " gSystem->Load(\"libANALYSIS\");" << endl;
1266 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1267 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1269 TIter next(fPackages);
1272 Bool_t hasSTEERBase = kFALSE;
1273 Bool_t hasESD = kFALSE;
1274 Bool_t hasAOD = kFALSE;
1275 Bool_t hasANALYSIS = kFALSE;
1276 Bool_t hasANALYSISalice = kFALSE;
1277 Bool_t hasCORRFW = kFALSE;
1278 while ((obj=next())) {
1279 pkgname = obj->GetName();
1280 if (pkgname == "STEERBase" ||
1281 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1282 if (pkgname == "ESD" ||
1283 pkgname == "ESD.par") hasESD = kTRUE;
1284 if (pkgname == "AOD" ||
1285 pkgname == "AOD.par") hasAOD = kTRUE;
1286 if (pkgname == "ANALYSIS" ||
1287 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1288 if (pkgname == "ANALYSISalice" ||
1289 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1290 if (pkgname == "CORRFW" ||
1291 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
1293 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1294 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1295 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1296 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1297 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1298 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1299 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1300 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1301 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1302 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1303 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1304 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1305 out << "// Compile other par packages" << endl;
1307 while ((obj=next())) {
1308 pkgname = obj->GetName();
1309 if (pkgname == "STEERBase" ||
1310 pkgname == "STEERBase.par" ||
1312 pkgname == "ESD.par" ||
1314 pkgname == "AOD.par" ||
1315 pkgname == "ANALYSIS" ||
1316 pkgname == "ANALYSIS.par" ||
1317 pkgname == "ANALYSISalice" ||
1318 pkgname == "ANALYSISalice.par" ||
1319 pkgname == "CORRFW" ||
1320 pkgname == "CORRFW.par") continue;
1321 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1324 out << "// include path" << endl;
1325 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1326 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1327 if (fAdditionalLibs.Length()) {
1328 out << "// Add aditional AliRoot libraries" << endl;
1329 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1332 while((str=(TObjString*)next())) {
1333 if (str->GetString().Contains(".so"))
1334 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1336 if (list) delete list;
1339 out << "// analysis source to be compiled at runtime (if any)" << endl;
1340 if (fAnalysisSource.Length()) {
1341 TObjArray *list = fAnalysisSource.Tokenize(" ");
1344 while((str=(TObjString*)next())) {
1345 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1347 if (list) delete list;
1350 out << "// connect to AliEn and make the chain" << endl;
1351 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1352 if (IsUsingTags()) {
1353 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1355 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1357 out << "// read the analysis manager from file" << endl;
1358 out << " TFile *file = TFile::Open(\"analysis.root\");" << endl;
1359 out << " if (!file) return;" << endl;
1360 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1361 out << " AliAnalysisManager *mgr = 0;" << endl;
1362 out << " TKey *key;" << endl;
1363 out << " while ((key=(TKey*)nextkey())) {" << endl;
1364 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1365 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1366 out << " };" << endl;
1367 out << " if (!mgr) {" << endl;
1368 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1369 out << " return;" << endl;
1370 out << " }" << endl << endl;
1371 out << " mgr->PrintStatus();" << endl;
1372 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1373 out << " timer.Stop();" << endl;
1374 out << " timer.Print();" << endl;
1375 out << "}" << endl << endl;
1376 if (IsUsingTags()) {
1377 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1379 out << "// Create a chain using tags from the xml file." << endl;
1380 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1381 out << " if (!coll) {" << endl;
1382 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1383 out << " return NULL;" << endl;
1384 out << " }" << endl;
1385 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1386 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1387 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1388 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1389 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1390 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1391 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1392 out << " // Check if the cuts configuration file was provided" << endl;
1393 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1394 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1395 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1396 out << " }" << endl;
1397 if (fFriendChainName=="") {
1398 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1400 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1401 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1402 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1404 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1405 out << " chain->ls();" << endl;
1406 out << " return chain;" << endl;
1407 out << "}" << endl << endl;
1408 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1409 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1410 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1411 msg += " AliLHCTagCuts *lhcCuts,\n";
1412 msg += " AliDetectorTagCuts *detCuts,\n";
1413 msg += " AliEventTagCuts *evCuts)";
1414 Info("WriteAnalysisMacro", msg.Data());
1417 if (!IsUsingTags() || fFriendChainName!="") {
1418 out <<"//________________________________________________________________________________" << endl;
1419 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1421 out << "// Create a chain using url's from xml file" << endl;
1422 out << " TString treename = type;" << endl;
1423 out << " treename.ToLower();" << endl;
1424 out << " treename += \"Tree\";" << endl;
1425 out << " printf(\"***************************************\\n\");" << endl;
1426 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
1427 out << " printf(\"***************************************\\n\");" << endl;
1428 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1429 out << " if (!coll) {" << endl;
1430 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1431 out << " return NULL;" << endl;
1432 out << " }" << endl;
1433 out << " TChain *chain = new TChain(treename);" << endl;
1434 if(fFriendChainName!="") {
1435 out << " TChain *chainFriend = new TChain(treename);" << endl;
1437 out << " coll->Reset();" << endl;
1438 out << " while (coll->Next()) {" << endl;
1439 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
1440 if(fFriendChainName!="") {
1441 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
1442 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1443 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1444 out << " chainFriend->Add(fileFriend.Data());" << endl;
1446 out << " }" << endl;
1447 out << " if (!chain->GetNtrees()) {" << endl;
1448 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1449 out << " return NULL;" << endl;
1450 out << " }" << endl;
1451 if(fFriendChainName!="") {
1452 out << " chain->AddFriend(chainFriend);" << endl;
1454 out << " return chain;" << endl;
1455 out << "}" << endl << endl;
1458 out <<"//________________________________________________________________________________" << endl;
1459 out << "Bool_t SetupPar(const char *package) {" << endl;
1460 out << "// Compile the package and set it up." << endl;
1461 out << " TString pkgdir = package;" << endl;
1462 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1463 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1464 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
1465 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
1466 out << " // Check for BUILD.sh and execute" << endl;
1467 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1468 out << " printf(\"*******************************\\n\");" << endl;
1469 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
1470 out << " printf(\"*******************************\\n\");" << endl;
1471 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1472 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1473 out << " gSystem->ChangeDirectory(cdir);" << endl;
1474 out << " return kFALSE;" << endl;
1475 out << " }" << endl;
1476 out << " } else {" << endl;
1477 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1478 out << " gSystem->ChangeDirectory(cdir);" << endl;
1479 out << " return kFALSE;" << endl;
1480 out << " }" << endl;
1481 out << " // Check for SETUP.C and execute" << endl;
1482 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1483 out << " printf(\"*******************************\\n\");" << endl;
1484 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
1485 out << " printf(\"*******************************\\n\");" << endl;
1486 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1487 out << " } else {" << endl;
1488 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1489 out << " gSystem->ChangeDirectory(cdir);" << endl;
1490 out << " return kFALSE;" << endl;
1491 out << " }" << endl;
1492 out << " // Restore original workdir" << endl;
1493 out << " gSystem->ChangeDirectory(cdir);" << endl;
1494 out << " return kTRUE;" << endl;
1497 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1499 Bool_t copy = kTRUE;
1500 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1503 TString workdir = gGrid->GetHomeDirectory();
1504 workdir += fGridWorkingDir;
1505 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1506 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1507 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1508 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1509 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1511 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1512 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1516 //______________________________________________________________________________
1517 void AliAnalysisAlien::WriteExecutable()
1519 // Generate the alien executable script.
1520 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1522 out.open(fExecutable.Data(), ios::out);
1524 Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1527 out << "#!/bin/bash" << endl;
1528 out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1529 out << "echo \"=========================================\"" << endl;
1530 out << "echo \"############## PATH : ##############\"" << endl;
1531 out << "echo $PATH" << endl;
1532 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1533 out << "echo $LD_LIBRARY_PATH" << endl;
1534 out << "echo \"############## ROOTSYS : ##############\"" << endl;
1535 out << "echo $ROOTSYS" << endl;
1536 out << "echo \"############## which root : ##############\"" << endl;
1537 out << "which root" << endl;
1538 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1539 out << "echo $ALICE_ROOT" << endl;
1540 out << "echo \"############## which aliroot : ##############\"" << endl;
1541 out << "which aliroot" << endl;
1542 out << "echo \"=========================================\"" << endl << endl;
1543 // if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1544 out << "root -b -q ";
1545 out << fAnalysisMacro.Data() << endl << endl;
1546 out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1548 Bool_t copy = kTRUE;
1549 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1552 TString workdir = gGrid->GetHomeDirectory();
1553 workdir += fGridWorkingDir;
1554 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1555 if (FileExists(executable)) gGrid->Rm(executable);
1556 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1557 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1561 //______________________________________________________________________________
1562 void AliAnalysisAlien::WriteValidationScript()
1564 // Generate the alien validation script.
1565 // Generate the validation script
1568 Error("WriteValidationScript", "Alien connection required");
1571 TString out_stream = "";
1572 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1573 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1575 out.open("validate.sh", ios::out);
1576 out << "#!/bin/bash" << endl;
1577 out << "##################################################" << endl;
1578 out << "validateout=`dirname $0`" << endl;
1579 out << "validatetime=`date`" << endl;
1580 out << "validated=\"0\";" << endl;
1581 out << "error=0" << endl;
1582 out << "if [ -z $validateout ]" << endl;
1583 out << "then" << endl;
1584 out << " validateout=\".\"" << endl;
1585 out << "fi" << endl << endl;
1586 out << "cd $validateout;" << endl;
1587 out << "validateworkdir=`pwd`;" << endl << endl;
1588 out << "echo \"*******************************************************\"" << out_stream << endl;
1589 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
1591 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
1592 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
1593 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
1594 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
1595 out << "ls -la ./" << out_stream << endl;
1596 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
1597 out << "##################################################" << endl;
1600 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
1601 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
1602 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
1605 out << "if [ ! -f stderr ] ; then" << endl;
1606 out << " error=1" << endl;
1607 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
1608 out << " echo \"Error = $error\" " << out_stream << endl;
1609 out << "fi" << endl;
1611 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
1612 out << " error=1" << endl;
1613 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
1614 out << " echo \"$parArch\" " << out_stream << endl;
1615 out << " echo \"Error = $error\" " << out_stream << endl;
1616 out << "fi" << endl;
1618 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
1619 out << " error=1" << endl;
1620 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
1621 out << " echo \"$segViol\" " << out_stream << endl;
1622 out << " echo \"Error = $error\" " << out_stream << endl;
1623 out << "fi" << endl;
1625 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
1626 out << " error=1" << endl;
1627 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
1628 out << " echo \"$segFault\" " << out_stream << endl;
1629 out << " echo \"Error = $error\" " << out_stream << endl;
1630 out << "fi" << endl;
1632 // Part dedicated to the specific analyses running into the train
1634 TObjArray *arr = fOutputFiles.Tokenize(" ");
1636 TString output_file;
1637 while ((os=(TObjString*)next1())) {
1638 output_file = os->GetString();
1639 Int_t index = output_file.Index("@");
1640 if (index > 0) output_file.Remove(index);
1641 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1642 out << " error=1" << endl;
1643 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
1644 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1645 out << "fi" << endl;
1648 out << "if [ $error = 0 ] ; then" << endl;
1649 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
1650 out << "fi" << endl;
1652 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
1653 out << "echo \"*******************************************************\"" << out_stream << endl;
1654 out << "cd -" << endl;
1655 out << "exit $error" << endl;
1657 Bool_t copy = kTRUE;
1658 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1661 TString workdir = gGrid->GetHomeDirectory();
1662 workdir += fGridWorkingDir;
1663 Info("CreateJDL", "\n##### Copying validation script <validate.sh> to your AliEn working space");
1664 if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1665 TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));