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 "TGridJobStatusList.h"
34 #include "TGridJobStatus.h"
35 #include "TFileMerger.h"
36 #include "AliAnalysisManager.h"
37 #include "AliVEventHandler.h"
38 #include "AliAnalysisDataContainer.h"
39 #include "AliAnalysisAlien.h"
41 ClassImp(AliAnalysisAlien)
43 //______________________________________________________________________________
44 AliAnalysisAlien::AliAnalysisAlien()
49 fSplitMaxInputFileNumber(0),
51 fMasterResubmitThreshold(0),
93 //______________________________________________________________________________
94 AliAnalysisAlien::AliAnalysisAlien(const char *name)
95 :AliAnalysisGrid(name),
99 fSplitMaxInputFileNumber(0),
101 fMasterResubmitThreshold(0),
109 fExecutableCommand(),
143 //______________________________________________________________________________
144 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
145 :AliAnalysisGrid(other),
147 fPrice(other.fPrice),
149 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
150 fMaxInitFailed(other.fMaxInitFailed),
151 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
152 fNtestFiles(other.fNtestFiles),
153 fNrunsPerMaster(other.fNrunsPerMaster),
154 fMaxMergeFiles(other.fMaxMergeFiles),
155 fNsubmitted(other.fNsubmitted),
156 fProductionMode(other.fProductionMode),
157 fRunNumbers(other.fRunNumbers),
158 fExecutable(other.fExecutable),
159 fExecutableCommand(other.fExecutableCommand),
160 fArguments(other.fArguments),
161 fAnalysisMacro(other.fAnalysisMacro),
162 fAnalysisSource(other.fAnalysisSource),
163 fAdditionalLibs(other.fAdditionalLibs),
164 fSplitMode(other.fSplitMode),
165 fAPIVersion(other.fAPIVersion),
166 fROOTVersion(other.fROOTVersion),
167 fAliROOTVersion(other.fAliROOTVersion),
168 fExternalPackages(other.fExternalPackages),
170 fGridWorkingDir(other.fGridWorkingDir),
171 fGridDataDir(other.fGridDataDir),
172 fDataPattern(other.fDataPattern),
173 fGridOutputDir(other.fGridOutputDir),
174 fOutputArchive(other.fOutputArchive),
175 fOutputFiles(other.fOutputFiles),
176 fInputFormat(other.fInputFormat),
177 fDatasetName(other.fDatasetName),
178 fJDLName(other.fJDLName),
179 fMergeExcludes(other.fMergeExcludes),
180 fIncludePath(other.fIncludePath),
181 fCloseSE(other.fCloseSE),
182 fFriendChainName(other.fFriendChainName),
183 fJobTag(other.fJobTag),
184 fOutputSingle(other.fOutputSingle),
185 fRunPrefix(other.fRunPrefix),
190 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
191 fRunRange[0] = other.fRunRange[0];
192 fRunRange[1] = other.fRunRange[1];
193 if (other.fInputFiles) {
194 fInputFiles = new TObjArray();
195 TIter next(other.fInputFiles);
197 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
198 fInputFiles->SetOwner();
200 if (other.fPackages) {
201 fPackages = new TObjArray();
202 TIter next(other.fPackages);
204 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
205 fPackages->SetOwner();
209 //______________________________________________________________________________
210 AliAnalysisAlien::~AliAnalysisAlien()
213 if (fGridJDL) delete fGridJDL;
214 if (fInputFiles) delete fInputFiles;
215 if (fPackages) delete fPackages;
218 //______________________________________________________________________________
219 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
222 if (this != &other) {
223 AliAnalysisGrid::operator=(other);
224 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
225 fPrice = other.fPrice;
227 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
228 fMaxInitFailed = other.fMaxInitFailed;
229 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
230 fNtestFiles = other.fNtestFiles;
231 fNrunsPerMaster = other.fNrunsPerMaster;
232 fMaxMergeFiles = other.fMaxMergeFiles;
233 fNsubmitted = other.fNsubmitted;
234 fProductionMode = other.fProductionMode;
235 fRunNumbers = other.fRunNumbers;
236 fExecutable = other.fExecutable;
237 fExecutableCommand = other.fExecutableCommand;
238 fArguments = other.fArguments;
239 fAnalysisMacro = other.fAnalysisMacro;
240 fAnalysisSource = other.fAnalysisSource;
241 fAdditionalLibs = other.fAdditionalLibs;
242 fSplitMode = other.fSplitMode;
243 fAPIVersion = other.fAPIVersion;
244 fROOTVersion = other.fROOTVersion;
245 fAliROOTVersion = other.fAliROOTVersion;
246 fExternalPackages = other.fExternalPackages;
248 fGridWorkingDir = other.fGridWorkingDir;
249 fGridDataDir = other.fGridDataDir;
250 fDataPattern = other.fDataPattern;
251 fGridOutputDir = other.fGridOutputDir;
252 fOutputArchive = other.fOutputArchive;
253 fOutputFiles = other.fOutputFiles;
254 fInputFormat = other.fInputFormat;
255 fDatasetName = other.fDatasetName;
256 fJDLName = other.fJDLName;
257 fMergeExcludes = other.fMergeExcludes;
258 fIncludePath = other.fIncludePath;
259 fCloseSE = other.fCloseSE;
260 fFriendChainName = other.fFriendChainName;
261 fJobTag = other.fJobTag;
262 fOutputSingle = other.fOutputSingle;
263 fRunPrefix = other.fRunPrefix;
264 if (other.fInputFiles) {
265 fInputFiles = new TObjArray();
266 TIter next(other.fInputFiles);
268 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
269 fInputFiles->SetOwner();
271 if (other.fPackages) {
272 fPackages = new TObjArray();
273 TIter next(other.fPackages);
275 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
276 fPackages->SetOwner();
282 //______________________________________________________________________________
283 void AliAnalysisAlien::AddIncludePath(const char *path)
285 // Add include path in the remote analysis macro.
287 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
288 else fIncludePath += Form("-I%s ", path);
291 //______________________________________________________________________________
292 void AliAnalysisAlien::AddRunNumber(Int_t run)
294 // Add a run number to the list of runs to be processed.
295 if (fRunNumbers.Length()) fRunNumbers += " ";
296 fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
299 //______________________________________________________________________________
300 void AliAnalysisAlien::AddRunNumber(const char* run)
302 // Add a run number to the list of runs to be processed.
303 if (fRunNumbers.Length()) fRunNumbers += " ";
307 //______________________________________________________________________________
308 void AliAnalysisAlien::AddDataFile(const char *lfn)
310 // Adds a data file to the input to be analysed. The file should be a valid LFN
311 // or point to an existing file in the alien workdir.
312 if (!fInputFiles) fInputFiles = new TObjArray();
313 fInputFiles->Add(new TObjString(lfn));
316 //______________________________________________________________________________
317 void AliAnalysisAlien::AddExternalPackage(const char *package)
319 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
320 if (fExternalPackages) fExternalPackages += " ";
321 fExternalPackages += package;
324 //______________________________________________________________________________
325 Bool_t AliAnalysisAlien::Connect()
327 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
328 if (gGrid && gGrid->IsConnected()) return kTRUE;
329 if (!gSystem->Getenv("alien_API_USER")) {
330 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
331 gSystem->Getenv("UID"));
335 Info("Connect", "Trying to connect to AliEn ...");
336 TGrid::Connect("alien://");
338 if (!gGrid || !gGrid->IsConnected()) {
339 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
342 fUser = gGrid->GetUser();
343 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
347 //______________________________________________________________________________
348 void AliAnalysisAlien::CdWork()
350 // Check validity of alien workspace. Create directory if possible.
352 Error("CdWork", "Alien connection required");
355 TString homedir = gGrid->GetHomeDirectory();
356 TString workdir = homedir + fGridWorkingDir;
357 if (DirectoryExists(workdir)) {
361 // Work directory not existing - create it
363 if (gGrid->Mkdir(workdir)) {
364 gGrid->Cd(fGridWorkingDir);
365 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
367 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
368 workdir.Data(), homedir.Data());
369 fGridWorkingDir = "";
373 //______________________________________________________________________________
374 Bool_t AliAnalysisAlien::CheckInputData()
376 // Check validity of input data. If necessary, create xml files.
377 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
378 if (!fGridDataDir.Length()) {
379 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
382 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
385 // Process declared files
386 Bool_t is_collection = kFALSE;
387 Bool_t is_xml = kFALSE;
388 Bool_t use_tags = kFALSE;
389 Bool_t checked = kFALSE;
392 TString workdir = gGrid->GetHomeDirectory();
393 workdir += fGridWorkingDir;
396 TIter next(fInputFiles);
397 while ((objstr=(TObjString*)next())) {
400 file += objstr->GetString();
401 // Store full lfn path
402 if (FileExists(file)) objstr->SetString(file);
404 file = objstr->GetName();
405 if (!FileExists(objstr->GetName())) {
406 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
407 objstr->GetName(), workdir.Data());
411 Bool_t iscoll, isxml, usetags;
412 CheckDataType(file, iscoll, isxml, usetags);
415 is_collection = iscoll;
418 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
420 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
421 Error("CheckInputData", "Some conflict was found in the types of inputs");
427 // Process requested run numbers
428 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
429 // Check validity of alien data directory
430 if (!fGridDataDir.Length()) {
431 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
434 if (!DirectoryExists(fGridDataDir)) {
435 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
439 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
443 if (checked && !is_xml) {
444 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
447 // Check validity of run number(s)
451 TString schunk, schunk2;
455 use_tags = fDataPattern.Contains("tag");
456 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
458 if (use_tags != fDataPattern.Contains("tag")) {
459 Error("CheckInputData", "Cannot mix input files using/not using tags");
462 if (fRunNumbers.Length()) {
463 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
464 arr = fRunNumbers.Tokenize(" ");
466 while ((os=(TObjString*)next())) {
467 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
468 if (!DirectoryExists(path)) {
469 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
472 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
473 TString msg = "\n##### file: ";
475 msg += " type: xml_collection;";
476 if (use_tags) msg += " using_tags: Yes";
477 else msg += " using_tags: No";
478 Info("CheckDataType", msg.Data());
479 if (fNrunsPerMaster<2) {
480 AddDataFile(Form("%s.xml", os->GetString().Data()));
483 if (((nruns-1)%fNrunsPerMaster) == 0) {
484 schunk = os->GetString();
486 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
487 schunk += Form("_%s.xml", os->GetString().Data());
493 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
494 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
495 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
496 if (!DirectoryExists(path)) {
497 // Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
500 path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
501 TString msg = "\n##### file: ";
503 msg += " type: xml_collection;";
504 if (use_tags) msg += " using_tags: Yes";
505 else msg += " using_tags: No";
506 Info("CheckDataType", msg.Data());
507 if (fNrunsPerMaster<2) {
508 AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
511 if (((nruns-1)%fNrunsPerMaster) == 0) {
512 schunk = Form("%s%d", fRunPrefix.Data(),irun);
514 schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
515 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
528 //______________________________________________________________________________
529 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
531 // Create dataset for the grid data directory + run number.
532 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
534 Error("CreateDataset", "Cannot create dataset with no grid connection");
540 TString workdir = gGrid->GetHomeDirectory();
541 workdir += fGridWorkingDir;
543 // Compose the 'find' command arguments
545 TString options = "-x collection ";
546 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
547 TString conditions = "";
552 TString schunk, schunk2;
553 TGridCollection *cbase=0, *cadd=0;
554 if (!fRunNumbers.Length() && !fRunRange[0]) {
555 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
556 // Make a single data collection from data directory.
558 if (!DirectoryExists(path)) {
559 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
563 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
564 else file = Form("%s.xml", gSystem->BaseName(path));
565 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest)) {
571 command += conditions;
572 printf("command: %s\n", command.Data());
573 TGridResult *res = gGrid->Command(command);
575 // Write standard output to file
576 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
578 if (!TestBit(AliAnalysisGrid::kTest) && !FileExists(file)) {
579 // Copy xml file to alien space
580 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
581 if (!FileExists(file)) {
582 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
585 // Update list of files to be processed.
587 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
591 if (fRunNumbers.Length()) {
592 TObjArray *arr = fRunNumbers.Tokenize(" ");
595 while ((os=(TObjString*)next())) {
596 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
597 if (!DirectoryExists(path)) continue;
599 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
600 else file = Form("%s.xml", os->GetString().Data());
601 // If local collection file does not exist, create it via 'find' command.
602 if (gSystem->AccessPathName(file)) {
607 command += conditions;
608 TGridResult *res = gGrid->Command(command);
610 // Write standard output to file
611 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
613 if (TestBit(AliAnalysisGrid::kTest)) break;
614 // Check if there is one run per master job.
615 if (fNrunsPerMaster<2) {
616 if (FileExists(file)) {
617 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
620 // Copy xml file to alien space
621 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
622 if (!FileExists(file)) {
623 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
629 if (((nruns-1)%fNrunsPerMaster) == 0) {
630 schunk = os->GetString();
631 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
633 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
634 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
638 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
641 schunk += Form("_%s.xml", os->GetString().Data());
642 if (FileExists(schunk)) {
643 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
646 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
647 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
648 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
649 if (!FileExists(schunk)) {
650 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
658 // Process a full run range.
659 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
660 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
661 if (!DirectoryExists(path)) continue;
663 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
664 else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
665 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
666 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
670 // If local collection file does not exist, create it via 'find' command.
671 if (gSystem->AccessPathName(file)) {
676 command += conditions;
677 TGridResult *res = gGrid->Command(command);
679 // Write standard output to file
680 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
682 if (TestBit(AliAnalysisGrid::kTest)) break;
683 // Check if there is one run per master job.
684 if (fNrunsPerMaster<2) {
685 if (FileExists(file)) {
686 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
689 // Copy xml file to alien space
690 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
691 if (!FileExists(file)) {
692 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
697 // Check if the collection for the chunk exist locally.
698 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
699 if (FileExists(fInputFiles->At(nchunk)->GetName())) continue;
700 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
701 if (((nruns-1)%fNrunsPerMaster) == 0) {
702 schunk = Form("%s%d", fRunPrefix.Data(), irun);
703 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
705 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
709 schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
710 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
714 if (FileExists(schunk)) {
715 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
718 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
719 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
720 if (FileExists(schunk)) {
721 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
724 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
725 if (!FileExists(schunk)) {
726 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
735 //______________________________________________________________________________
736 Bool_t AliAnalysisAlien::CreateJDL()
738 // Generate a JDL file according to current settings. The name of the file is
739 // specified by fJDLName.
740 Bool_t error = kFALSE;
743 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
744 Bool_t generate = kTRUE;
745 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
747 Error("CreateJDL", "Alien connection required");
750 // Check validity of alien workspace
752 TString workdir = gGrid->GetHomeDirectory();
753 workdir += fGridWorkingDir;
757 Error("CreateJDL()", "Define some input files for your analysis.");
760 // Compose list of input files
761 // Check if output files were defined
762 if (!fOutputFiles.Length()) {
763 Error("CreateJDL", "You must define at least one output file");
766 // Check if an output directory was defined and valid
767 if (!fGridOutputDir.Length()) {
768 Error("CreateJDL", "You must define AliEn output directory");
771 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
772 if (!DirectoryExists(fGridOutputDir)) {
773 if (gGrid->Mkdir(fGridOutputDir)) {
774 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
776 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
782 // Exit if any error up to now
783 if (error) return kFALSE;
785 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
786 fGridJDL->SetExecutable(fExecutable);
787 // fGridJDL->SetTTL((UInt_t)fTTL);
788 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
789 if (fMaxInitFailed > 0)
790 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
791 if (fSplitMaxInputFileNumber > 0)
792 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
793 if (fSplitMode.Length())
794 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
795 // fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
796 if (fAliROOTVersion.Length())
797 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
798 if (fROOTVersion.Length())
799 fGridJDL->AddToPackages("ROOT", fROOTVersion);
800 if (fAPIVersion.Length())
801 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
802 if (!fExternalPackages.IsNull()) {
803 arr = fExternalPackages.Tokenize(" ");
805 while ((os=(TObjString*)next())) {
806 TString pkgname = os->GetString();
807 Int_t index = pkgname.Index("::");
808 TString pkgversion = pkgname(index+2, pkgname.Length());
809 pkgname.Remove(index);
810 fGridJDL->AddToPackages(pkgname, pkgversion);
814 fGridJDL->SetInputDataListFormat(fInputFormat);
815 fGridJDL->SetInputDataList("wn.xml");
816 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
817 TString analysisFile = fExecutable;
818 analysisFile.ReplaceAll(".sh", ".root");
819 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
820 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
821 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
822 if (fAdditionalLibs.Length()) {
823 arr = fAdditionalLibs.Tokenize(" ");
825 while ((os=(TObjString*)next())) {
826 if (os->GetString().Contains(".so")) continue;
827 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
832 TIter next(fPackages);
835 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
837 if (fOutputArchive.Length()) {
838 arr = fOutputArchive.Tokenize(" ");
840 while ((os=(TObjString*)next()))
841 if (!os->GetString().Contains("@") && fCloseSE.Length())
842 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
844 fGridJDL->AddToOutputArchive(os->GetString());
847 arr = fOutputFiles.Tokenize(" ");
849 while ((os=(TObjString*)next())) {
850 // Ignore ouputs in jdl that are also in outputarchive
851 TString sout = os->GetString();
852 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
853 if (fOutputArchive.Contains(sout)) continue;
854 if (!os->GetString().Contains("@") && fCloseSE.Length())
855 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
857 fGridJDL->AddToOutputSandbox(os->GetString());
860 // fGridJDL->SetPrice((UInt_t)fPrice);
861 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
862 TString validationScript = fExecutable;
863 validationScript.ReplaceAll(".sh", "_validation.sh");
864 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()));
865 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
866 // Write a jdl with 2 input parameters: collection name and output dir name.
869 // Copy jdl to grid workspace
871 if (TestBit(AliAnalysisGrid::kSubmit)) {
872 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
873 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
875 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
876 if (FileExists(locjdl)) gGrid->Rm(locjdl);
877 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
879 if (fAdditionalLibs.Length()) {
880 arr = fAdditionalLibs.Tokenize(" ");
883 while ((os=(TObjString*)next())) {
884 if (os->GetString().Contains(".so")) continue;
885 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
886 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
887 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
892 TIter next(fPackages);
894 while ((obj=next())) {
895 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
896 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
903 //______________________________________________________________________________
904 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
906 // Writes one or more JDL's corresponding to findex. If findex is negative,
907 // all run numbers are considered in one go (jdl). For non-negative indices
908 // they correspond to the indices in the array fInputFiles.
909 if (!fInputFiles) return kFALSE;
911 TString workdir = gGrid->GetHomeDirectory();
912 workdir += fGridWorkingDir;
914 if (!fRunNumbers.Length() && !fRunRange[0]) {
915 // One jdl with no parameters in case input data is specified by name.
916 TIter next(fInputFiles);
917 while ((os=(TObjString*)next()))
918 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
919 if (!fOutputSingle.IsNull())
920 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
922 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
924 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
925 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
926 if (!fOutputSingle.IsNull())
927 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
928 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
932 // Generate the JDL as a string
933 TString sjdl = fGridJDL->Generate();
935 index = sjdl.Index("Executable");
936 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
937 index = sjdl.Index("Split ");
938 if (index >= 0) sjdl.Insert(index, "\n# We split per SE or file\n");
939 index = sjdl.Index("SplitMaxInputFileNumber");
940 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
941 index = sjdl.Index("InputDataCollection");
942 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
943 index = sjdl.Index("InputFile");
944 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
945 index = sjdl.Index("InputDataList ");
946 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
947 index = sjdl.Index("InputDataListFormat");
948 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
949 index = sjdl.Index("Price");
950 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
951 index = sjdl.Index("Requirements");
952 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
953 index = sjdl.Index("Packages");
954 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
955 index = sjdl.Index("User =");
956 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
957 index = sjdl.Index("TTL");
958 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
959 index = sjdl.Index("OutputFile");
960 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
961 index = sjdl.Index("OutputDir");
962 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
963 index = sjdl.Index("OutputArchive");
964 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
965 index = sjdl.Index("MaxInitFailed");
966 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
967 index = sjdl.Index("MasterResubmitThreshold");
968 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
969 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
970 index = sjdl.Index("Validationcommand");
971 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
972 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
973 sjdl.ReplaceAll("(member", "\n (member");
974 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
975 sjdl.ReplaceAll("{", "{\n ");
976 sjdl.ReplaceAll("};", "\n};");
977 sjdl.ReplaceAll("{\n \n", "{\n");
978 sjdl.ReplaceAll("\n\n", "\n");
979 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
980 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
981 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
982 index = sjdl.Index("JDLVariables");
983 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
986 out.open(fJDLName.Data(), ios::out);
988 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
993 // Copy jdl to grid workspace
995 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
997 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
998 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1000 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1001 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1002 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1007 //______________________________________________________________________________
1008 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1010 // Returns true if file exists.
1011 if (!gGrid) return kFALSE;
1012 TGridResult *res = gGrid->Ls(lfn);
1013 if (!res) return kFALSE;
1014 TMap *map = dynamic_cast<TMap*>(res->At(0));
1019 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1020 if (!objs || !objs->GetString().Length()) {
1028 //______________________________________________________________________________
1029 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1031 // Returns true if directory exists. Can be also a path.
1032 if (!gGrid) return kFALSE;
1033 // Check if dirname is a path
1034 TString dirstripped = dirname;
1035 dirstripped = dirstripped.Strip();
1036 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1037 TString dir = gSystem->BaseName(dirstripped);
1039 TString path = gSystem->DirName(dirstripped);
1040 TGridResult *res = gGrid->Ls(path, "-F");
1041 if (!res) return kFALSE;
1045 while ((map=dynamic_cast<TMap*>(next()))) {
1046 obj = map->GetValue("name");
1048 if (dir == obj->GetName()) {
1057 //______________________________________________________________________________
1058 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1060 // Check input data type.
1061 is_collection = kFALSE;
1065 Error("CheckDataType", "No connection to grid");
1068 is_collection = IsCollection(lfn);
1069 TString msg = "\n##### file: ";
1071 if (is_collection) {
1072 msg += " type: raw_collection;";
1073 // special treatment for collections
1075 // check for tag files in the collection
1076 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1078 msg += " using_tags: No (unknown)";
1079 Info("CheckDataType", msg.Data());
1082 const char* typeStr = res->GetKey(0, "origLFN");
1083 if (!typeStr || !strlen(typeStr)) {
1084 msg += " using_tags: No (unknown)";
1085 Info("CheckDataType", msg.Data());
1088 TString file = typeStr;
1089 use_tags = file.Contains(".tag");
1090 if (use_tags) msg += " using_tags: Yes";
1091 else msg += " using_tags: No";
1092 Info("CheckDataType", msg.Data());
1097 is_xml = slfn.Contains(".xml");
1099 // Open xml collection and check if there are tag files inside
1100 msg += " type: xml_collection;";
1101 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1103 msg += " using_tags: No (unknown)";
1104 Info("CheckDataType", msg.Data());
1107 TMap *map = coll->Next();
1109 msg += " using_tags: No (unknown)";
1110 Info("CheckDataType", msg.Data());
1113 map = (TMap*)map->GetValue("");
1115 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1116 use_tags = file.Contains(".tag");
1118 if (use_tags) msg += " using_tags: Yes";
1119 else msg += " using_tags: No";
1120 Info("CheckDataType", msg.Data());
1123 use_tags = slfn.Contains(".tag");
1124 if (slfn.Contains(".root")) msg += " type: root file;";
1125 else msg += " type: unhnown file;";
1126 if (use_tags) msg += " using_tags: Yes";
1127 else msg += " using_tags: No";
1128 Info("CheckDataType", msg.Data());
1131 //______________________________________________________________________________
1132 void AliAnalysisAlien::EnablePackage(const char *package)
1134 // Enables a par file supposed to exist in the current directory.
1135 TString pkg(package);
1136 pkg.ReplaceAll(".par", "");
1138 if (gSystem->AccessPathName(pkg)) {
1139 Error("EnablePackage", "Package %s not found", pkg.Data());
1142 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1143 Info("EnablePackage", "AliEn plugin will use .par packages");
1144 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1146 fPackages = new TObjArray();
1147 fPackages->SetOwner();
1149 fPackages->Add(new TObjString(pkg));
1152 //______________________________________________________________________________
1153 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1155 // Get job status for all jobs with jobid>jobidstart.
1156 static char mstatus[20];
1162 TGridJobStatusList *list = gGrid->Ps("");
1163 if (!list) return mstatus;
1164 Int_t nentries = list->GetSize();
1165 TGridJobStatus *status;
1167 for (Int_t ijob=0; ijob<nentries; ijob++) {
1168 status = (TGridJobStatus *)list->At(ijob);
1169 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1170 if (pid<jobidstart) continue;
1171 if (pid == lastid) {
1172 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1174 switch (status->GetStatus()) {
1175 case TGridJobStatus::kWAITING:
1177 case TGridJobStatus::kRUNNING:
1179 case TGridJobStatus::kABORTED:
1180 case TGridJobStatus::kFAIL:
1181 case TGridJobStatus::kUNKNOWN:
1183 case TGridJobStatus::kDONE:
1192 //______________________________________________________________________________
1193 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1195 // Returns true if file is a collection. Functionality duplicated from
1196 // TAlien::Type() because we don't want to directly depend on TAlien.
1198 Error("IsCollection", "No connection to grid");
1201 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1202 if (!res) return kFALSE;
1203 const char* typeStr = res->GetKey(0, "type");
1204 if (!typeStr || !strlen(typeStr)) return kFALSE;
1205 if (!strcmp(typeStr, "collection")) return kTRUE;
1210 //______________________________________________________________________________
1211 void AliAnalysisAlien::Print(Option_t *) const
1213 // Print current plugin settings.
1214 printf("### AliEn analysis plugin current settings ###\n");
1215 printf("= Production mode:______________________________ %d\n", fProductionMode);
1216 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1217 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1218 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1220 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1221 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1222 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1223 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1224 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1225 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1226 if (fRunNumbers.Length())
1227 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1229 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1230 if (!fRunRange[0] && !fRunNumbers.Length()) {
1231 TIter next(fInputFiles);
1234 while ((obj=next())) list += obj->GetName();
1235 printf("= Input files to be processed: _________________ %s\n", list.Data());
1237 if (TestBit(AliAnalysisGrid::kTest))
1238 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1239 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1240 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1241 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1242 printf("=====================================================================\n");
1243 printf("= Job price: ___________________________________ %d\n", fPrice);
1244 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1245 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1246 if (fMaxInitFailed>0)
1247 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1248 if (fMasterResubmitThreshold>0)
1249 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1250 if (fNrunsPerMaster>0)
1251 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1252 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1253 printf("= Name of the generated execution script: ______ %s\n",fExecutable.Data());
1254 if (fArguments.Length())
1255 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1256 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1257 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1258 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1259 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1261 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1262 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1263 if (fIncludePath.Data())
1264 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1265 if (fCloseSE.Length())
1266 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1267 if (fFriendChainName.Length())
1268 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1270 TIter next(fPackages);
1273 while ((obj=next())) list += obj->GetName();
1274 printf("= Par files to be used: ________________________ %s\n", list.Data());
1278 //______________________________________________________________________________
1279 void AliAnalysisAlien::SetDefaults()
1281 // Set default values for everything. What cannot be filled will be left empty.
1282 if (fGridJDL) delete fGridJDL;
1283 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1286 fSplitMaxInputFileNumber = 100;
1288 fMasterResubmitThreshold = 0;
1292 fNrunsPerMaster = 1;
1293 fMaxMergeFiles = 100;
1295 fExecutable = "analysis.sh";
1296 fExecutableCommand = "root -b -q";
1298 fAnalysisMacro = "myAnalysis.C";
1299 fAnalysisSource = "";
1300 fAdditionalLibs = "";
1304 fAliROOTVersion = "";
1305 fUser = ""; // Your alien user name
1306 fGridWorkingDir = "";
1307 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1308 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1309 fFriendChainName = "";
1310 fGridOutputDir = "output";
1311 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1312 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1313 fInputFormat = "xml-single";
1314 fJDLName = "analysis.jdl";
1315 fJobTag = "Automatically generated analysis JDL";
1316 fMergeExcludes = "";
1319 //______________________________________________________________________________
1320 Bool_t AliAnalysisAlien::MergeOutputs()
1322 // Merge analysis outputs existing in the AliEn space.
1323 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1324 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1326 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1329 // Get the output path
1330 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1331 if (!DirectoryExists(fGridOutputDir)) {
1332 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1335 if (!fOutputFiles.Length()) {
1336 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1339 TObjArray *list = fOutputFiles.Tokenize(" ");
1343 TString output_file;
1344 TString output_chunk;
1345 TString previous_chunk;
1346 Int_t count_chunk = 0;
1347 Int_t count_zero = fMaxMergeFiles;
1348 Bool_t merged = kTRUE;
1349 while((str=(TObjString*)next())) {
1350 output_file = str->GetString();
1351 Int_t index = output_file.Index("@");
1352 if (index > 0) output_file.Remove(index);
1353 // Skip already merged outputs
1354 if (!gSystem->AccessPathName(output_file)) {
1355 Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1358 if (fMergeExcludes.Length() &&
1359 fMergeExcludes.Contains(output_file.Data())) continue;
1360 // Perform a 'find' command in the output directory, looking for registered outputs
1361 command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1362 printf("command: %s\n", command.Data());
1363 TGridResult *res = gGrid->Command(command);
1365 TFileMerger *fm = 0;
1368 previous_chunk = "";
1370 // Check if there is a merge operation to resume
1371 output_chunk = output_file;
1372 output_chunk.ReplaceAll(".root", "_*.root");
1373 if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1375 for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1377 Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1381 output_chunk = output_file;
1382 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1383 printf("%s\n", output_chunk.Data());
1385 if (gSystem->AccessPathName(output_chunk)) continue;
1386 // Merged file with chunks up to <count_chunk> found
1387 printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1388 previous_chunk = output_chunk;
1392 count_zero = fMaxMergeFiles;
1393 while ((map=(TMap*)nextmap())) {
1394 // Loop 'find' results and get next LFN
1395 if (count_zero == fMaxMergeFiles) {
1396 // First file in chunk - create file merger and add previous chunk if any.
1397 fm = new TFileMerger(kFALSE);
1398 fm->SetFastMethod(kTRUE);
1399 if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1400 output_chunk = output_file;
1401 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1403 // If last file found, put merged results in the output file
1404 if (map == res->Last()) output_chunk = output_file;
1405 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1406 if (!objs || !objs->GetString().Length()) {
1407 // Nothing found - skip this output
1412 // Add file to be merged and decrement chunk counter.
1413 fm->AddFile(objs->GetString());
1415 if (count_zero==0 || map == res->Last()) {
1416 fm->OutputFile(output_chunk);
1417 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1418 // Nothing found - skip this output
1419 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1424 // Merge the outputs, then go to next chunk
1426 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1432 Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1433 gSystem->Unlink(previous_chunk);
1435 if (map == res->Last()) {
1441 count_zero = fMaxMergeFiles;
1442 previous_chunk = output_chunk;
1447 Error("MergeOutputs", "Terminate() will NOT be executed");
1452 //______________________________________________________________________________
1453 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1455 // Use the output files connected to output containers from the analysis manager
1456 // rather than the files defined by SetOutputFiles
1457 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1458 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1460 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1463 //______________________________________________________________________________
1464 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1466 // Start remote grid analysis.
1468 // Check if output files have to be taken from the analysis manager
1469 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1470 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1471 if (!mgr || !mgr->IsInitialized()) {
1472 Error("StartAnalysis", "You need an initialized analysis manager for this");
1476 TIter next(mgr->GetOutputs());
1477 AliAnalysisDataContainer *output;
1478 while ((output=(AliAnalysisDataContainer*)next())) {
1479 const char *filename = output->GetFileName();
1480 if (!(strcmp(filename, "default"))) {
1481 if (!mgr->GetOutputEventHandler()) continue;
1482 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1484 if (fOutputFiles.Contains(filename)) continue;
1485 if (fOutputFiles.Length()) fOutputFiles += " ";
1486 fOutputFiles += filename;
1488 // Add extra files registered to the analysis manager
1489 if (mgr->GetExtraFiles().Length()) {
1490 if (fOutputFiles.Length()) fOutputFiles += " ";
1491 fOutputFiles += mgr->GetExtraFiles();
1494 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1495 if (TestBit(AliAnalysisGrid::kOffline)) {
1496 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1497 \n there nor any job run. You can revise the JDL and analysis \
1498 \n macro then run the same in \"submit\" mode.");
1499 } else if (TestBit(AliAnalysisGrid::kTest)) {
1500 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1502 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1503 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1504 \n space and job submitted.");
1505 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1506 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1509 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1513 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1517 if (!CheckInputData()) {
1518 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1521 CreateDataset(fDataPattern);
1522 WriteAnalysisFile();
1523 WriteAnalysisMacro();
1525 WriteValidationScript();
1526 if (!CreateJDL()) return kFALSE;
1527 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1528 if (TestBit(AliAnalysisGrid::kTest)) {
1529 // Locally testing the analysis
1530 Info("StartAnalysis", "\n_______________________________________________________________________ \
1531 \n Running analysis script in a daughter shell as on a worker node \
1532 \n_______________________________________________________________________");
1533 TObjArray *list = fOutputFiles.Tokenize(" ");
1536 TString output_file;
1537 while((str=(TObjString*)next())) {
1538 output_file = str->GetString();
1539 Int_t index = output_file.Index("@");
1540 if (index > 0) output_file.Remove(index);
1541 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1544 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1545 TString validationScript = fExecutable;
1546 validationScript.ReplaceAll(".sh", "_validation.sh");
1547 gSystem->Exec(Form("bash %s",validationScript.Data()));
1548 // gSystem->Exec("cat stdout");
1551 // Check if submitting is managed by LPM manager
1552 if (fProductionMode) {
1553 TString prodfile = fJDLName;
1554 prodfile.ReplaceAll(".jdl", ".prod");
1555 WriteProductionFile(prodfile);
1556 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1559 // Submit AliEn job(s)
1560 gGrid->Cd(fGridOutputDir);
1563 if (!fRunNumbers.Length() && !fRunRange[0]) {
1564 // Submit a given xml or a set of runs
1565 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1566 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1568 const char *cjobId = res->GetKey(0,"jobId");
1570 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1573 Info("StartAnalysis", "\n_______________________________________________________________________ \
1574 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1575 \n_______________________________________________________________________",
1576 fJDLName.Data(), cjobId);
1582 // Submit for a range of enumeration of runs.
1586 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1587 \n You may exit at any time and terminate the job later using the option <terminate> \
1588 \n ##################################################################################", jobID.Data());
1589 gSystem->Exec("aliensh");
1593 //______________________________________________________________________________
1594 void AliAnalysisAlien::Submit()
1596 // Submit all master jobs.
1597 Int_t nmasterjobs = fInputFiles->GetEntries();
1598 Long_t tshoot = gSystem->Now();
1599 if (!fNsubmitted) SubmitNext();
1600 while (fNsubmitted < nmasterjobs) {
1601 Long_t now = gSystem->Now();
1602 if ((now-tshoot)>30000) {
1609 //______________________________________________________________________________
1610 void AliAnalysisAlien::SubmitNext()
1612 // Submit next bunch of master jobs if the queue is free.
1613 static Bool_t iscalled = kFALSE;
1614 static Int_t firstmaster = 0;
1615 static Int_t lastmaster = 0;
1616 static Int_t npermaster = 0;
1617 if (iscalled) return;
1619 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1620 Int_t ntosubmit = 0;
1623 if (!fNsubmitted) ntosubmit = 1;
1625 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1626 printf("=== master %d: %s\n", lastmaster, status.Data());
1627 // If last master not split, just return
1628 if (status != "SPLIT") {iscalled = kFALSE; return;}
1629 // No more than 100 waiting jobs
1630 if (nwaiting>100) {iscalled = kFALSE; return;}
1631 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
1632 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1633 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
1634 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1636 Int_t nmasterjobs = fInputFiles->GetEntries();
1637 for (Int_t i=0; i<ntosubmit; i++) {
1638 // Submit for a range of enumeration of runs.
1639 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1641 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1642 printf("********* %s\n",query.Data());
1643 res = gGrid->Command(query);
1645 TString cjobId1 = res->GetKey(0,"jobId");
1646 if (!cjobId1.Length()) {
1647 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1651 Info("StartAnalysis", "\n_______________________________________________________________________ \
1652 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1653 \n_______________________________________________________________________",
1654 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1657 lastmaster = cjobId1.Atoi();
1658 if (!firstmaster) firstmaster = lastmaster;
1667 //______________________________________________________________________________
1668 void AliAnalysisAlien::WriteAnalysisFile()
1670 // Write current analysis manager into the file <analysisFile>
1671 TString analysisFile = fExecutable;
1672 analysisFile.ReplaceAll(".sh", ".root");
1673 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1674 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1675 if (!mgr || !mgr->IsInitialized()) {
1676 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1679 // Check analysis type
1681 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1682 handler = (TObject*)mgr->GetInputEventHandler();
1684 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1685 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1687 TDirectory *cdir = gDirectory;
1688 TFile *file = TFile::Open(analysisFile, "RECREATE");
1693 if (cdir) cdir->cd();
1694 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1696 Bool_t copy = kTRUE;
1697 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1700 TString workdir = gGrid->GetHomeDirectory();
1701 workdir += fGridWorkingDir;
1702 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1703 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1704 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1708 //______________________________________________________________________________
1709 void AliAnalysisAlien::WriteAnalysisMacro()
1711 // Write the analysis macro that will steer the analysis in grid mode.
1712 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1714 out.open(fAnalysisMacro.Data(), ios::out);
1716 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1719 TString func = fAnalysisMacro;
1720 TString type = "ESD";
1721 TString comment = "// Analysis using ";
1722 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1723 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1727 if (type!="AOD" && fFriendChainName!="") {
1728 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1731 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1732 else comment += " data";
1733 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1734 func.ReplaceAll(".C", "");
1735 out << "void " << func.Data() << "()" << endl;
1737 out << comment.Data() << endl;
1738 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1739 out << " TStopwatch timer;" << endl;
1740 out << " timer.Start();" << endl << endl;
1741 out << "// load base root libraries" << endl;
1742 out << " gSystem->Load(\"libTree\");" << endl;
1743 out << " gSystem->Load(\"libGeom\");" << endl;
1744 out << " gSystem->Load(\"libVMC\");" << endl;
1745 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
1746 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
1747 out << "// Load analysis framework libraries" << endl;
1749 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1750 out << " gSystem->Load(\"libESD\");" << endl;
1751 out << " gSystem->Load(\"libAOD\");" << endl;
1752 out << " gSystem->Load(\"libANALYSIS\");" << endl;
1753 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1754 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1756 TIter next(fPackages);
1759 Bool_t hasSTEERBase = kFALSE;
1760 Bool_t hasESD = kFALSE;
1761 Bool_t hasAOD = kFALSE;
1762 Bool_t hasANALYSIS = kFALSE;
1763 Bool_t hasANALYSISalice = kFALSE;
1764 Bool_t hasCORRFW = kFALSE;
1765 while ((obj=next())) {
1766 pkgname = obj->GetName();
1767 if (pkgname == "STEERBase" ||
1768 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1769 if (pkgname == "ESD" ||
1770 pkgname == "ESD.par") hasESD = kTRUE;
1771 if (pkgname == "AOD" ||
1772 pkgname == "AOD.par") hasAOD = kTRUE;
1773 if (pkgname == "ANALYSIS" ||
1774 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1775 if (pkgname == "ANALYSISalice" ||
1776 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1777 if (pkgname == "CORRFW" ||
1778 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
1780 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1781 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1782 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1783 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1784 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1785 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1786 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1787 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1788 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1789 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1790 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1791 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1792 out << "// Compile other par packages" << endl;
1794 while ((obj=next())) {
1795 pkgname = obj->GetName();
1796 if (pkgname == "STEERBase" ||
1797 pkgname == "STEERBase.par" ||
1799 pkgname == "ESD.par" ||
1801 pkgname == "AOD.par" ||
1802 pkgname == "ANALYSIS" ||
1803 pkgname == "ANALYSIS.par" ||
1804 pkgname == "ANALYSISalice" ||
1805 pkgname == "ANALYSISalice.par" ||
1806 pkgname == "CORRFW" ||
1807 pkgname == "CORRFW.par") continue;
1808 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1811 out << "// include path" << endl;
1812 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1813 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1814 if (fAdditionalLibs.Length()) {
1815 out << "// Add aditional AliRoot libraries" << endl;
1816 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1819 while((str=(TObjString*)next())) {
1820 if (str->GetString().Contains(".so"))
1821 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1823 if (list) delete list;
1826 out << "// analysis source to be compiled at runtime (if any)" << endl;
1827 if (fAnalysisSource.Length()) {
1828 TObjArray *list = fAnalysisSource.Tokenize(" ");
1831 while((str=(TObjString*)next())) {
1832 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1834 if (list) delete list;
1837 out << "// connect to AliEn and make the chain" << endl;
1838 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1839 if (IsUsingTags()) {
1840 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1842 if(fFriendChainName!="AliAOD.VertexingHF.root") {
1843 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1845 out << " // Check if the macro to create the chain was provided" << endl;
1846 out << " if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1847 out << " ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1848 out << " return;" << endl;
1849 out << " }" << endl;
1850 out << " gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1851 out << " TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1854 out << "// read the analysis manager from file" << endl;
1855 TString analysisFile = fExecutable;
1856 analysisFile.ReplaceAll(".sh", ".root");
1857 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1858 out << " if (!file) return;" << endl;
1859 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1860 out << " AliAnalysisManager *mgr = 0;" << endl;
1861 out << " TKey *key;" << endl;
1862 out << " while ((key=(TKey*)nextkey())) {" << endl;
1863 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1864 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1865 out << " };" << endl;
1866 out << " if (!mgr) {" << endl;
1867 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1868 out << " return;" << endl;
1869 out << " }" << endl << endl;
1870 out << " mgr->PrintStatus();" << endl;
1871 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1872 out << " timer.Stop();" << endl;
1873 out << " timer.Print();" << endl;
1874 out << "}" << endl << endl;
1875 if (IsUsingTags()) {
1876 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1878 out << "// Create a chain using tags from the xml file." << endl;
1879 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1880 out << " if (!coll) {" << endl;
1881 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1882 out << " return NULL;" << endl;
1883 out << " }" << endl;
1884 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1885 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1886 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1887 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1888 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1889 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1890 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1891 out << " // Check if the cuts configuration file was provided" << endl;
1892 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1893 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1894 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1895 out << " }" << endl;
1896 if (fFriendChainName=="") {
1897 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1899 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1900 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1901 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1903 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1904 out << " chain->ls();" << endl;
1905 out << " return chain;" << endl;
1906 out << "}" << endl << endl;
1907 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1908 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1909 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1910 msg += " AliLHCTagCuts *lhcCuts,\n";
1911 msg += " AliDetectorTagCuts *detCuts,\n";
1912 msg += " AliEventTagCuts *evCuts)";
1913 Info("WriteAnalysisMacro", msg.Data());
1916 if (!IsUsingTags() || fFriendChainName!="") {
1917 out <<"//________________________________________________________________________________" << endl;
1918 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1920 out << "// Create a chain using url's from xml file" << endl;
1921 out << " TString treename = type;" << endl;
1922 out << " treename.ToLower();" << endl;
1923 out << " treename += \"Tree\";" << endl;
1924 out << " printf(\"***************************************\\n\");" << endl;
1925 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
1926 out << " printf(\"***************************************\\n\");" << endl;
1927 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1928 out << " if (!coll) {" << endl;
1929 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1930 out << " return NULL;" << endl;
1931 out << " }" << endl;
1932 out << " TChain *chain = new TChain(treename);" << endl;
1933 if(fFriendChainName!="") {
1934 out << " TChain *chainFriend = new TChain(treename);" << endl;
1936 out << " coll->Reset();" << endl;
1937 out << " while (coll->Next()) {" << endl;
1938 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
1939 if(fFriendChainName!="") {
1940 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
1941 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1942 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1943 out << " chainFriend->Add(fileFriend.Data());" << endl;
1945 out << " }" << endl;
1946 out << " if (!chain->GetNtrees()) {" << endl;
1947 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1948 out << " return NULL;" << endl;
1949 out << " }" << endl;
1950 if(fFriendChainName!="") {
1951 out << " chain->AddFriend(chainFriend);" << endl;
1953 out << " return chain;" << endl;
1954 out << "}" << endl << endl;
1957 out <<"//________________________________________________________________________________" << endl;
1958 out << "Bool_t SetupPar(const char *package) {" << endl;
1959 out << "// Compile the package and set it up." << endl;
1960 out << " TString pkgdir = package;" << endl;
1961 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1962 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1963 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
1964 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
1965 out << " // Check for BUILD.sh and execute" << endl;
1966 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1967 out << " printf(\"*******************************\\n\");" << endl;
1968 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
1969 out << " printf(\"*******************************\\n\");" << endl;
1970 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1971 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1972 out << " gSystem->ChangeDirectory(cdir);" << endl;
1973 out << " return kFALSE;" << endl;
1974 out << " }" << endl;
1975 out << " } else {" << endl;
1976 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1977 out << " gSystem->ChangeDirectory(cdir);" << endl;
1978 out << " return kFALSE;" << endl;
1979 out << " }" << endl;
1980 out << " // Check for SETUP.C and execute" << endl;
1981 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1982 out << " printf(\"*******************************\\n\");" << endl;
1983 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
1984 out << " printf(\"*******************************\\n\");" << endl;
1985 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1986 out << " } else {" << endl;
1987 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1988 out << " gSystem->ChangeDirectory(cdir);" << endl;
1989 out << " return kFALSE;" << endl;
1990 out << " }" << endl;
1991 out << " // Restore original workdir" << endl;
1992 out << " gSystem->ChangeDirectory(cdir);" << endl;
1993 out << " return kTRUE;" << endl;
1996 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1998 Bool_t copy = kTRUE;
1999 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2002 TString workdir = gGrid->GetHomeDirectory();
2003 workdir += fGridWorkingDir;
2004 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2005 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2006 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2007 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2008 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2010 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2011 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2015 //______________________________________________________________________________
2016 void AliAnalysisAlien::WriteExecutable()
2018 // Generate the alien executable script.
2019 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2021 out.open(fExecutable.Data(), ios::out);
2023 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2026 out << "#!/bin/bash" << endl;
2027 out << "echo \"=========================================\"" << endl;
2028 out << "echo \"############## PATH : ##############\"" << endl;
2029 out << "echo $PATH" << endl;
2030 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2031 out << "echo $LD_LIBRARY_PATH" << endl;
2032 out << "echo \"############## ROOTSYS : ##############\"" << endl;
2033 out << "echo $ROOTSYS" << endl;
2034 out << "echo \"############## which root : ##############\"" << endl;
2035 out << "which root" << endl;
2036 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2037 out << "echo $ALICE_ROOT" << endl;
2038 out << "echo \"############## which aliroot : ##############\"" << endl;
2039 out << "which aliroot" << endl;
2040 out << "echo \"=========================================\"" << endl << endl;
2041 // Make sure we can properly compile par files
2042 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2043 out << fExecutableCommand << " ";
2044 out << fAnalysisMacro.Data() << endl << endl;
2045 out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
2047 Bool_t copy = kTRUE;
2048 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2051 TString workdir = gGrid->GetHomeDirectory();
2052 TString bindir = Form("%s/bin", workdir.Data());
2053 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2054 workdir += fGridWorkingDir;
2055 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2056 if (FileExists(executable)) gGrid->Rm(executable);
2057 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2058 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2062 //______________________________________________________________________________
2063 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2065 // Write the production file to be submitted by LPM manager. The format is:
2066 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2067 // Next lines: full_path_to_dataset XXX (XXX is a string)
2068 // To submit, one has to: submit jdl XXX for all lines
2070 out.open(filename, ios::out);
2072 Error("WriteProductionFile", "Bad file name: %s", filename);
2075 TString workdir = gGrid->GetHomeDirectory();
2076 workdir += fGridWorkingDir;
2077 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2078 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2079 out << locjdl << " " << njobspermaster << endl;
2080 Int_t nmasterjobs = fInputFiles->GetEntries();
2081 for (Int_t i=0; i<nmasterjobs; i++) {
2082 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2084 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
2085 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
2088 //______________________________________________________________________________
2089 void AliAnalysisAlien::WriteValidationScript()
2091 // Generate the alien validation script.
2092 // Generate the validation script
2094 TString validationScript = fExecutable;
2095 validationScript.ReplaceAll(".sh", "_validation.sh");
2097 Error("WriteValidationScript", "Alien connection required");
2100 TString out_stream = "";
2101 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2102 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2104 out.open(validationScript, ios::out);
2105 out << "#!/bin/bash" << endl;
2106 out << "##################################################" << endl;
2107 out << "validateout=`dirname $0`" << endl;
2108 out << "validatetime=`date`" << endl;
2109 out << "validated=\"0\";" << endl;
2110 out << "error=0" << endl;
2111 out << "if [ -z $validateout ]" << endl;
2112 out << "then" << endl;
2113 out << " validateout=\".\"" << endl;
2114 out << "fi" << endl << endl;
2115 out << "cd $validateout;" << endl;
2116 out << "validateworkdir=`pwd`;" << endl << endl;
2117 out << "echo \"*******************************************************\"" << out_stream << endl;
2118 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
2120 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
2121 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
2122 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
2123 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2124 out << "ls -la ./" << out_stream << endl;
2125 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
2126 out << "##################################################" << endl;
2129 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2130 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2131 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2134 out << "if [ ! -f stderr ] ; then" << endl;
2135 out << " error=1" << endl;
2136 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
2137 out << " echo \"Error = $error\" " << out_stream << endl;
2138 out << "fi" << endl;
2140 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2141 out << " error=1" << endl;
2142 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
2143 out << " echo \"$parArch\" " << out_stream << endl;
2144 out << " echo \"Error = $error\" " << out_stream << endl;
2145 out << "fi" << endl;
2147 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2148 out << " error=1" << endl;
2149 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
2150 out << " echo \"$segViol\" " << out_stream << endl;
2151 out << " echo \"Error = $error\" " << out_stream << endl;
2152 out << "fi" << endl;
2154 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2155 out << " error=1" << endl;
2156 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
2157 out << " echo \"$segFault\" " << out_stream << endl;
2158 out << " echo \"Error = $error\" " << out_stream << endl;
2159 out << "fi" << endl;
2161 // Part dedicated to the specific analyses running into the train
2163 TObjArray *arr = fOutputFiles.Tokenize(" ");
2165 TString output_file;
2166 while ((os=(TObjString*)next1())) {
2167 output_file = os->GetString();
2168 Int_t index = output_file.Index("@");
2169 if (index > 0) output_file.Remove(index);
2170 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2171 out << " error=1" << endl;
2172 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
2173 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2174 out << "fi" << endl;
2177 out << "if ! [ -f outputs_valid ] ; then" << endl;
2178 out << " error=1" << endl;
2179 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2180 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2181 out << "fi" << endl;
2183 out << "if [ $error = 0 ] ; then" << endl;
2184 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
2185 out << "fi" << endl;
2187 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2188 out << "echo \"*******************************************************\"" << out_stream << endl;
2189 out << "cd -" << endl;
2190 out << "exit $error" << endl;
2192 Bool_t copy = kTRUE;
2193 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2196 TString workdir = gGrid->GetHomeDirectory();
2197 workdir += fGridWorkingDir;
2198 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
2199 if (FileExists(validationScript)) gGrid->Rm(validationScript);
2200 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));