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),
95 //______________________________________________________________________________
96 AliAnalysisAlien::AliAnalysisAlien(const char *name)
97 :AliAnalysisGrid(name),
101 fSplitMaxInputFileNumber(0),
103 fMasterResubmitThreshold(0),
112 fExecutableCommand(),
147 //______________________________________________________________________________
148 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
149 :AliAnalysisGrid(other),
151 fPrice(other.fPrice),
153 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
154 fMaxInitFailed(other.fMaxInitFailed),
155 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
156 fNtestFiles(other.fNtestFiles),
157 fNrunsPerMaster(other.fNrunsPerMaster),
158 fMaxMergeFiles(other.fMaxMergeFiles),
159 fNsubmitted(other.fNsubmitted),
160 fProductionMode(other.fProductionMode),
161 fOutputToRunNo(other.fOutputToRunNo),
162 fRunNumbers(other.fRunNumbers),
163 fExecutable(other.fExecutable),
164 fExecutableCommand(other.fExecutableCommand),
165 fArguments(other.fArguments),
166 fExecutableArgs(other.fExecutableArgs),
167 fAnalysisMacro(other.fAnalysisMacro),
168 fAnalysisSource(other.fAnalysisSource),
169 fAdditionalLibs(other.fAdditionalLibs),
170 fSplitMode(other.fSplitMode),
171 fAPIVersion(other.fAPIVersion),
172 fROOTVersion(other.fROOTVersion),
173 fAliROOTVersion(other.fAliROOTVersion),
174 fExternalPackages(other.fExternalPackages),
176 fGridWorkingDir(other.fGridWorkingDir),
177 fGridDataDir(other.fGridDataDir),
178 fDataPattern(other.fDataPattern),
179 fGridOutputDir(other.fGridOutputDir),
180 fOutputArchive(other.fOutputArchive),
181 fOutputFiles(other.fOutputFiles),
182 fInputFormat(other.fInputFormat),
183 fDatasetName(other.fDatasetName),
184 fJDLName(other.fJDLName),
185 fMergeExcludes(other.fMergeExcludes),
186 fIncludePath(other.fIncludePath),
187 fCloseSE(other.fCloseSE),
188 fFriendChainName(other.fFriendChainName),
189 fJobTag(other.fJobTag),
190 fOutputSingle(other.fOutputSingle),
191 fRunPrefix(other.fRunPrefix),
196 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
197 fRunRange[0] = other.fRunRange[0];
198 fRunRange[1] = other.fRunRange[1];
199 if (other.fInputFiles) {
200 fInputFiles = new TObjArray();
201 TIter next(other.fInputFiles);
203 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
204 fInputFiles->SetOwner();
206 if (other.fPackages) {
207 fPackages = new TObjArray();
208 TIter next(other.fPackages);
210 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
211 fPackages->SetOwner();
215 //______________________________________________________________________________
216 AliAnalysisAlien::~AliAnalysisAlien()
219 if (fGridJDL) delete fGridJDL;
220 if (fInputFiles) delete fInputFiles;
221 if (fPackages) delete fPackages;
224 //______________________________________________________________________________
225 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
228 if (this != &other) {
229 AliAnalysisGrid::operator=(other);
230 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
231 fPrice = other.fPrice;
233 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
234 fMaxInitFailed = other.fMaxInitFailed;
235 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
236 fNtestFiles = other.fNtestFiles;
237 fNrunsPerMaster = other.fNrunsPerMaster;
238 fMaxMergeFiles = other.fMaxMergeFiles;
239 fNsubmitted = other.fNsubmitted;
240 fProductionMode = other.fProductionMode;
241 fOutputToRunNo = other.fOutputToRunNo;
242 fRunNumbers = other.fRunNumbers;
243 fExecutable = other.fExecutable;
244 fExecutableCommand = other.fExecutableCommand;
245 fArguments = other.fArguments;
246 fExecutableArgs = other.fExecutableArgs;
247 fAnalysisMacro = other.fAnalysisMacro;
248 fAnalysisSource = other.fAnalysisSource;
249 fAdditionalLibs = other.fAdditionalLibs;
250 fSplitMode = other.fSplitMode;
251 fAPIVersion = other.fAPIVersion;
252 fROOTVersion = other.fROOTVersion;
253 fAliROOTVersion = other.fAliROOTVersion;
254 fExternalPackages = other.fExternalPackages;
256 fGridWorkingDir = other.fGridWorkingDir;
257 fGridDataDir = other.fGridDataDir;
258 fDataPattern = other.fDataPattern;
259 fGridOutputDir = other.fGridOutputDir;
260 fOutputArchive = other.fOutputArchive;
261 fOutputFiles = other.fOutputFiles;
262 fInputFormat = other.fInputFormat;
263 fDatasetName = other.fDatasetName;
264 fJDLName = other.fJDLName;
265 fMergeExcludes = other.fMergeExcludes;
266 fIncludePath = other.fIncludePath;
267 fCloseSE = other.fCloseSE;
268 fFriendChainName = other.fFriendChainName;
269 fJobTag = other.fJobTag;
270 fOutputSingle = other.fOutputSingle;
271 fRunPrefix = other.fRunPrefix;
272 if (other.fInputFiles) {
273 fInputFiles = new TObjArray();
274 TIter next(other.fInputFiles);
276 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
277 fInputFiles->SetOwner();
279 if (other.fPackages) {
280 fPackages = new TObjArray();
281 TIter next(other.fPackages);
283 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
284 fPackages->SetOwner();
290 //______________________________________________________________________________
291 void AliAnalysisAlien::AddIncludePath(const char *path)
293 // Add include path in the remote analysis macro.
295 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
296 else fIncludePath += Form("-I%s ", path);
299 //______________________________________________________________________________
300 void AliAnalysisAlien::AddRunNumber(Int_t run)
302 // Add a run number to the list of runs to be processed.
303 if (fRunNumbers.Length()) fRunNumbers += " ";
304 fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
307 //______________________________________________________________________________
308 void AliAnalysisAlien::AddRunNumber(const char* run)
310 // Add a run number to the list of runs to be processed.
311 if (fRunNumbers.Length()) fRunNumbers += " ";
315 //______________________________________________________________________________
316 void AliAnalysisAlien::AddDataFile(const char *lfn)
318 // Adds a data file to the input to be analysed. The file should be a valid LFN
319 // or point to an existing file in the alien workdir.
320 if (!fInputFiles) fInputFiles = new TObjArray();
321 fInputFiles->Add(new TObjString(lfn));
324 //______________________________________________________________________________
325 void AliAnalysisAlien::AddExternalPackage(const char *package)
327 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
328 if (fExternalPackages) fExternalPackages += " ";
329 fExternalPackages += package;
332 //______________________________________________________________________________
333 Bool_t AliAnalysisAlien::Connect()
335 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
336 if (gGrid && gGrid->IsConnected()) return kTRUE;
337 if (!gSystem->Getenv("alien_API_USER")) {
338 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
339 gSystem->Getenv("UID"));
343 Info("Connect", "Trying to connect to AliEn ...");
344 TGrid::Connect("alien://");
346 if (!gGrid || !gGrid->IsConnected()) {
347 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
350 fUser = gGrid->GetUser();
351 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
355 //______________________________________________________________________________
356 void AliAnalysisAlien::CdWork()
358 // Check validity of alien workspace. Create directory if possible.
360 Error("CdWork", "Alien connection required");
363 TString homedir = gGrid->GetHomeDirectory();
364 TString workdir = homedir + fGridWorkingDir;
365 if (DirectoryExists(workdir)) {
369 // Work directory not existing - create it
371 if (gGrid->Mkdir(workdir)) {
372 gGrid->Cd(fGridWorkingDir);
373 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
375 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
376 workdir.Data(), homedir.Data());
377 fGridWorkingDir = "";
381 //______________________________________________________________________________
382 Bool_t AliAnalysisAlien::CheckInputData()
384 // Check validity of input data. If necessary, create xml files.
385 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
386 if (!fGridDataDir.Length()) {
387 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
390 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
393 // Process declared files
394 Bool_t is_collection = kFALSE;
395 Bool_t is_xml = kFALSE;
396 Bool_t use_tags = kFALSE;
397 Bool_t checked = kFALSE;
400 TString workdir = gGrid->GetHomeDirectory();
401 workdir += fGridWorkingDir;
404 TIter next(fInputFiles);
405 while ((objstr=(TObjString*)next())) {
408 file += objstr->GetString();
409 // Store full lfn path
410 if (FileExists(file)) objstr->SetString(file);
412 file = objstr->GetName();
413 if (!FileExists(objstr->GetName())) {
414 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
415 objstr->GetName(), workdir.Data());
419 Bool_t iscoll, isxml, usetags;
420 CheckDataType(file, iscoll, isxml, usetags);
423 is_collection = iscoll;
426 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
428 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
429 Error("CheckInputData", "Some conflict was found in the types of inputs");
435 // Process requested run numbers
436 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
437 // Check validity of alien data directory
438 if (!fGridDataDir.Length()) {
439 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
442 if (!DirectoryExists(fGridDataDir)) {
443 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
447 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
451 if (checked && !is_xml) {
452 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
455 // Check validity of run number(s)
459 TString schunk, schunk2;
463 use_tags = fDataPattern.Contains("tag");
464 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
466 if (use_tags != fDataPattern.Contains("tag")) {
467 Error("CheckInputData", "Cannot mix input files using/not using tags");
470 if (fRunNumbers.Length()) {
471 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
472 arr = fRunNumbers.Tokenize(" ");
474 while ((os=(TObjString*)next())) {
475 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
476 if (!DirectoryExists(path)) {
477 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
480 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
481 TString msg = "\n##### file: ";
483 msg += " type: xml_collection;";
484 if (use_tags) msg += " using_tags: Yes";
485 else msg += " using_tags: No";
486 Info("CheckDataType", msg.Data());
487 if (fNrunsPerMaster<2) {
488 AddDataFile(Form("%s.xml", os->GetString().Data()));
491 if (((nruns-1)%fNrunsPerMaster) == 0) {
492 schunk = os->GetString();
494 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
495 schunk += Form("_%s.xml", os->GetString().Data());
501 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
502 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
503 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
504 if (!DirectoryExists(path)) {
505 // Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
508 path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
509 TString msg = "\n##### file: ";
511 msg += " type: xml_collection;";
512 if (use_tags) msg += " using_tags: Yes";
513 else msg += " using_tags: No";
514 Info("CheckDataType", msg.Data());
515 if (fNrunsPerMaster<2) {
516 AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
519 if (((nruns-1)%fNrunsPerMaster) == 0) {
520 schunk = Form("%s%d", fRunPrefix.Data(),irun);
522 schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
523 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
536 //______________________________________________________________________________
537 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
539 // Create dataset for the grid data directory + run number.
540 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
542 Error("CreateDataset", "Cannot create dataset with no grid connection");
548 TString workdir = gGrid->GetHomeDirectory();
549 workdir += fGridWorkingDir;
551 // Compose the 'find' command arguments
553 TString options = "-x collection ";
554 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
555 TString conditions = "";
560 TString schunk, schunk2;
561 TGridCollection *cbase=0, *cadd=0;
562 if (!fRunNumbers.Length() && !fRunRange[0]) {
563 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
564 // Make a single data collection from data directory.
566 if (!DirectoryExists(path)) {
567 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
571 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
572 else file = Form("%s.xml", gSystem->BaseName(path));
573 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest)) {
579 command += conditions;
580 printf("command: %s\n", command.Data());
581 TGridResult *res = gGrid->Command(command);
583 // Write standard output to file
584 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
586 if (!TestBit(AliAnalysisGrid::kTest) && !FileExists(file)) {
587 // Copy xml file to alien space
588 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
589 if (!FileExists(file)) {
590 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
593 // Update list of files to be processed.
595 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
599 if (fRunNumbers.Length()) {
600 TObjArray *arr = fRunNumbers.Tokenize(" ");
603 while ((os=(TObjString*)next())) {
604 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
605 if (!DirectoryExists(path)) continue;
607 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
608 else file = Form("%s.xml", os->GetString().Data());
609 // If local collection file does not exist, create it via 'find' command.
610 if (gSystem->AccessPathName(file)) {
615 command += conditions;
616 TGridResult *res = gGrid->Command(command);
618 // Write standard output to file
619 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
621 if (TestBit(AliAnalysisGrid::kTest)) break;
622 // Check if there is one run per master job.
623 if (fNrunsPerMaster<2) {
624 if (FileExists(file)) {
625 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
628 // Copy xml file to alien space
629 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
630 if (!FileExists(file)) {
631 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
637 if (((nruns-1)%fNrunsPerMaster) == 0) {
638 schunk = os->GetString();
639 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
641 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
642 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
646 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
649 schunk += Form("_%s.xml", os->GetString().Data());
650 if (FileExists(schunk)) {
651 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
654 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
655 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
656 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
657 if (!FileExists(schunk)) {
658 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
666 // Process a full run range.
667 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
668 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
669 if (!DirectoryExists(path)) continue;
671 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
672 else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
673 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
674 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
678 // If local collection file does not exist, create it via 'find' command.
679 if (gSystem->AccessPathName(file)) {
684 command += conditions;
685 TGridResult *res = gGrid->Command(command);
687 // Write standard output to file
688 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
690 if (TestBit(AliAnalysisGrid::kTest)) break;
691 // Check if there is one run per master job.
692 if (fNrunsPerMaster<2) {
693 if (FileExists(file)) {
694 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
697 // Copy xml file to alien space
698 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
699 if (!FileExists(file)) {
700 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
705 // Check if the collection for the chunk exist locally.
706 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
707 if (FileExists(fInputFiles->At(nchunk)->GetName())) continue;
708 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
709 if (((nruns-1)%fNrunsPerMaster) == 0) {
710 schunk = Form("%s%d", fRunPrefix.Data(), irun);
711 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
713 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
717 schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
718 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
722 if (FileExists(schunk)) {
723 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
726 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
727 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
728 if (FileExists(schunk)) {
729 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
732 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
733 if (!FileExists(schunk)) {
734 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
743 //______________________________________________________________________________
744 Bool_t AliAnalysisAlien::CreateJDL()
746 // Generate a JDL file according to current settings. The name of the file is
747 // specified by fJDLName.
748 Bool_t error = kFALSE;
751 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
752 Bool_t generate = kTRUE;
753 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
755 Error("CreateJDL", "Alien connection required");
758 // Check validity of alien workspace
760 TString workdir = gGrid->GetHomeDirectory();
761 workdir += fGridWorkingDir;
765 Error("CreateJDL()", "Define some input files for your analysis.");
768 // Compose list of input files
769 // Check if output files were defined
770 if (!fOutputFiles.Length()) {
771 Error("CreateJDL", "You must define at least one output file");
774 // Check if an output directory was defined and valid
775 if (!fGridOutputDir.Length()) {
776 Error("CreateJDL", "You must define AliEn output directory");
779 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
780 if (!DirectoryExists(fGridOutputDir)) {
781 if (gGrid->Mkdir(fGridOutputDir)) {
782 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
784 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
790 // Exit if any error up to now
791 if (error) return kFALSE;
793 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
794 fGridJDL->SetExecutable(fExecutable);
795 if (!fArguments.IsNull())
796 fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
797 // fGridJDL->SetTTL((UInt_t)fTTL);
798 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
799 if (fMaxInitFailed > 0)
800 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
801 if (fSplitMaxInputFileNumber > 0)
802 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
803 if (fSplitMode.Length())
804 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
805 // fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
806 if (fAliROOTVersion.Length())
807 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
808 if (fROOTVersion.Length())
809 fGridJDL->AddToPackages("ROOT", fROOTVersion);
810 if (fAPIVersion.Length())
811 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
812 if (!fExternalPackages.IsNull()) {
813 arr = fExternalPackages.Tokenize(" ");
815 while ((os=(TObjString*)next())) {
816 TString pkgname = os->GetString();
817 Int_t index = pkgname.Index("::");
818 TString pkgversion = pkgname(index+2, pkgname.Length());
819 pkgname.Remove(index);
820 fGridJDL->AddToPackages(pkgname, pkgversion);
824 fGridJDL->SetInputDataListFormat(fInputFormat);
825 fGridJDL->SetInputDataList("wn.xml");
826 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
827 TString analysisFile = fExecutable;
828 analysisFile.ReplaceAll(".sh", ".root");
829 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
830 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
831 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
832 if (fAdditionalLibs.Length()) {
833 arr = fAdditionalLibs.Tokenize(" ");
835 while ((os=(TObjString*)next())) {
836 if (os->GetString().Contains(".so")) continue;
837 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
842 TIter next(fPackages);
845 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
847 if (fOutputArchive.Length()) {
848 arr = fOutputArchive.Tokenize(" ");
850 while ((os=(TObjString*)next()))
851 if (!os->GetString().Contains("@") && fCloseSE.Length())
852 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
854 fGridJDL->AddToOutputArchive(os->GetString());
857 arr = fOutputFiles.Tokenize(" ");
859 while ((os=(TObjString*)next())) {
860 // Ignore ouputs in jdl that are also in outputarchive
861 TString sout = os->GetString();
862 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
863 if (fOutputArchive.Contains(sout)) continue;
864 if (!os->GetString().Contains("@") && fCloseSE.Length())
865 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
867 fGridJDL->AddToOutputSandbox(os->GetString());
870 // fGridJDL->SetPrice((UInt_t)fPrice);
871 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
872 TString validationScript = fExecutable;
873 validationScript.ReplaceAll(".sh", "_validation.sh");
874 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()));
875 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
876 // Write a jdl with 2 input parameters: collection name and output dir name.
879 // Copy jdl to grid workspace
881 // Check if an output directory was defined and valid
882 if (!fGridOutputDir.Length()) {
883 Error("CreateJDL", "You must define AliEn output directory");
886 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
887 if (!DirectoryExists(fGridOutputDir)) {
888 if (gGrid->Mkdir(fGridOutputDir)) {
889 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
891 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
897 if (TestBit(AliAnalysisGrid::kSubmit)) {
898 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
899 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
901 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
902 if (FileExists(locjdl)) gGrid->Rm(locjdl);
903 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
905 if (fAdditionalLibs.Length()) {
906 arr = fAdditionalLibs.Tokenize(" ");
909 while ((os=(TObjString*)next())) {
910 if (os->GetString().Contains(".so")) continue;
911 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
912 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
913 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
918 TIter next(fPackages);
920 while ((obj=next())) {
921 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
922 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
929 //______________________________________________________________________________
930 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
932 // Writes one or more JDL's corresponding to findex. If findex is negative,
933 // all run numbers are considered in one go (jdl). For non-negative indices
934 // they correspond to the indices in the array fInputFiles.
935 if (!fInputFiles) return kFALSE;
937 TString workdir = gGrid->GetHomeDirectory();
938 workdir += fGridWorkingDir;
940 if (!fRunNumbers.Length() && !fRunRange[0]) {
941 // One jdl with no parameters in case input data is specified by name.
942 TIter next(fInputFiles);
943 while ((os=(TObjString*)next()))
944 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
945 if (!fOutputSingle.IsNull())
946 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
948 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
950 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
951 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
952 if (!fOutputSingle.IsNull()) {
953 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
954 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()));
956 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
961 // Generate the JDL as a string
962 TString sjdl = fGridJDL->Generate();
964 index = sjdl.Index("Executable");
965 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
966 index = sjdl.Index("Split ");
967 if (index >= 0) sjdl.Insert(index, "\n# We split per SE or file\n");
968 index = sjdl.Index("SplitMaxInputFileNumber");
969 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
970 index = sjdl.Index("InputDataCollection");
971 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
972 index = sjdl.Index("InputFile");
973 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
974 index = sjdl.Index("InputDataList ");
975 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
976 index = sjdl.Index("InputDataListFormat");
977 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
978 index = sjdl.Index("Price");
979 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
980 index = sjdl.Index("Requirements");
981 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
982 index = sjdl.Index("Packages");
983 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
984 index = sjdl.Index("User =");
985 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
986 index = sjdl.Index("TTL");
987 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
988 index = sjdl.Index("OutputFile");
989 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
990 index = sjdl.Index("OutputDir");
991 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
992 index = sjdl.Index("OutputArchive");
993 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
994 index = sjdl.Index("MaxInitFailed");
995 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
996 index = sjdl.Index("MasterResubmitThreshold");
997 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
998 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
999 index = sjdl.Index("Validationcommand");
1000 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
1001 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1002 sjdl.ReplaceAll("(member", "\n (member");
1003 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1004 sjdl.ReplaceAll("{", "{\n ");
1005 sjdl.ReplaceAll("};", "\n};");
1006 sjdl.ReplaceAll("{\n \n", "{\n");
1007 sjdl.ReplaceAll("\n\n", "\n");
1008 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1009 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1010 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
1011 index = sjdl.Index("JDLVariables");
1012 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1013 // Write jdl to file
1015 out.open(fJDLName.Data(), ios::out);
1017 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1020 out << sjdl << endl;
1022 // Copy jdl to grid workspace
1024 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1026 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1027 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1028 if (fProductionMode)
1029 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1030 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1031 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1036 //______________________________________________________________________________
1037 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1039 // Returns true if file exists.
1040 if (!gGrid) return kFALSE;
1041 TGridResult *res = gGrid->Ls(lfn);
1042 if (!res) return kFALSE;
1043 TMap *map = dynamic_cast<TMap*>(res->At(0));
1048 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1049 if (!objs || !objs->GetString().Length()) {
1057 //______________________________________________________________________________
1058 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1060 // Returns true if directory exists. Can be also a path.
1061 if (!gGrid) return kFALSE;
1062 // Check if dirname is a path
1063 TString dirstripped = dirname;
1064 dirstripped = dirstripped.Strip();
1065 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1066 TString dir = gSystem->BaseName(dirstripped);
1068 TString path = gSystem->DirName(dirstripped);
1069 TGridResult *res = gGrid->Ls(path, "-F");
1070 if (!res) return kFALSE;
1074 while ((map=dynamic_cast<TMap*>(next()))) {
1075 obj = map->GetValue("name");
1077 if (dir == obj->GetName()) {
1086 //______________________________________________________________________________
1087 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1089 // Check input data type.
1090 is_collection = kFALSE;
1094 Error("CheckDataType", "No connection to grid");
1097 is_collection = IsCollection(lfn);
1098 TString msg = "\n##### file: ";
1100 if (is_collection) {
1101 msg += " type: raw_collection;";
1102 // special treatment for collections
1104 // check for tag files in the collection
1105 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1107 msg += " using_tags: No (unknown)";
1108 Info("CheckDataType", msg.Data());
1111 const char* typeStr = res->GetKey(0, "origLFN");
1112 if (!typeStr || !strlen(typeStr)) {
1113 msg += " using_tags: No (unknown)";
1114 Info("CheckDataType", msg.Data());
1117 TString file = typeStr;
1118 use_tags = file.Contains(".tag");
1119 if (use_tags) msg += " using_tags: Yes";
1120 else msg += " using_tags: No";
1121 Info("CheckDataType", msg.Data());
1126 is_xml = slfn.Contains(".xml");
1128 // Open xml collection and check if there are tag files inside
1129 msg += " type: xml_collection;";
1130 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1132 msg += " using_tags: No (unknown)";
1133 Info("CheckDataType", msg.Data());
1136 TMap *map = coll->Next();
1138 msg += " using_tags: No (unknown)";
1139 Info("CheckDataType", msg.Data());
1142 map = (TMap*)map->GetValue("");
1144 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1145 use_tags = file.Contains(".tag");
1147 if (use_tags) msg += " using_tags: Yes";
1148 else msg += " using_tags: No";
1149 Info("CheckDataType", msg.Data());
1152 use_tags = slfn.Contains(".tag");
1153 if (slfn.Contains(".root")) msg += " type: root file;";
1154 else msg += " type: unhnown file;";
1155 if (use_tags) msg += " using_tags: Yes";
1156 else msg += " using_tags: No";
1157 Info("CheckDataType", msg.Data());
1160 //______________________________________________________________________________
1161 void AliAnalysisAlien::EnablePackage(const char *package)
1163 // Enables a par file supposed to exist in the current directory.
1164 TString pkg(package);
1165 pkg.ReplaceAll(".par", "");
1167 if (gSystem->AccessPathName(pkg)) {
1168 Error("EnablePackage", "Package %s not found", pkg.Data());
1171 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1172 Info("EnablePackage", "AliEn plugin will use .par packages");
1173 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1175 fPackages = new TObjArray();
1176 fPackages->SetOwner();
1178 fPackages->Add(new TObjString(pkg));
1181 //______________________________________________________________________________
1182 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1184 // Get job status for all jobs with jobid>jobidstart.
1185 static char mstatus[20];
1191 TGridJobStatusList *list = gGrid->Ps("");
1192 if (!list) return mstatus;
1193 Int_t nentries = list->GetSize();
1194 TGridJobStatus *status;
1196 for (Int_t ijob=0; ijob<nentries; ijob++) {
1197 status = (TGridJobStatus *)list->At(ijob);
1198 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1199 if (pid<jobidstart) continue;
1200 if (pid == lastid) {
1201 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1203 switch (status->GetStatus()) {
1204 case TGridJobStatus::kWAITING:
1206 case TGridJobStatus::kRUNNING:
1208 case TGridJobStatus::kABORTED:
1209 case TGridJobStatus::kFAIL:
1210 case TGridJobStatus::kUNKNOWN:
1212 case TGridJobStatus::kDONE:
1221 //______________________________________________________________________________
1222 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1224 // Returns true if file is a collection. Functionality duplicated from
1225 // TAlien::Type() because we don't want to directly depend on TAlien.
1227 Error("IsCollection", "No connection to grid");
1230 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1231 if (!res) return kFALSE;
1232 const char* typeStr = res->GetKey(0, "type");
1233 if (!typeStr || !strlen(typeStr)) return kFALSE;
1234 if (!strcmp(typeStr, "collection")) return kTRUE;
1239 //______________________________________________________________________________
1240 void AliAnalysisAlien::Print(Option_t *) const
1242 // Print current plugin settings.
1243 printf("### AliEn analysis plugin current settings ###\n");
1244 printf("= Production mode:______________________________ %d\n", fProductionMode);
1245 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1246 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1247 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1249 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1250 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1251 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1252 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1253 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1254 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1255 if (fRunNumbers.Length())
1256 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1258 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1259 if (!fRunRange[0] && !fRunNumbers.Length()) {
1260 TIter next(fInputFiles);
1263 while ((obj=next())) list += obj->GetName();
1264 printf("= Input files to be processed: _________________ %s\n", list.Data());
1266 if (TestBit(AliAnalysisGrid::kTest))
1267 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1268 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1269 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1270 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1271 printf("=====================================================================\n");
1272 printf("= Job price: ___________________________________ %d\n", fPrice);
1273 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1274 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1275 if (fMaxInitFailed>0)
1276 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1277 if (fMasterResubmitThreshold>0)
1278 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1279 if (fNrunsPerMaster>0)
1280 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1281 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1282 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1283 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
1284 if (fArguments.Length())
1285 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1286 if (fExecutableArgs.Length())
1287 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1288 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1289 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1290 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1291 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1293 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1294 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1295 if (fIncludePath.Data())
1296 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1297 if (fCloseSE.Length())
1298 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1299 if (fFriendChainName.Length())
1300 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1302 TIter next(fPackages);
1305 while ((obj=next())) list += obj->GetName();
1306 printf("= Par files to be used: ________________________ %s\n", list.Data());
1310 //______________________________________________________________________________
1311 void AliAnalysisAlien::SetDefaults()
1313 // Set default values for everything. What cannot be filled will be left empty.
1314 if (fGridJDL) delete fGridJDL;
1315 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1318 fSplitMaxInputFileNumber = 100;
1320 fMasterResubmitThreshold = 0;
1324 fNrunsPerMaster = 1;
1325 fMaxMergeFiles = 100;
1327 fExecutable = "analysis.sh";
1328 fExecutableCommand = "root -b -q";
1330 fExecutableArgs = "";
1331 fAnalysisMacro = "myAnalysis.C";
1332 fAnalysisSource = "";
1333 fAdditionalLibs = "";
1337 fAliROOTVersion = "";
1338 fUser = ""; // Your alien user name
1339 fGridWorkingDir = "";
1340 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1341 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1342 fFriendChainName = "";
1343 fGridOutputDir = "output";
1344 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1345 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1346 fInputFormat = "xml-single";
1347 fJDLName = "analysis.jdl";
1348 fJobTag = "Automatically generated analysis JDL";
1349 fMergeExcludes = "";
1352 //______________________________________________________________________________
1353 Bool_t AliAnalysisAlien::MergeOutputs()
1355 // Merge analysis outputs existing in the AliEn space.
1356 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1357 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1359 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1362 // Get the output path
1363 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1364 if (!DirectoryExists(fGridOutputDir)) {
1365 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1368 if (!fOutputFiles.Length()) {
1369 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1372 TObjArray *list = fOutputFiles.Tokenize(" ");
1376 TString output_file;
1377 TString output_chunk;
1378 TString previous_chunk;
1379 Int_t count_chunk = 0;
1380 Int_t count_zero = fMaxMergeFiles;
1381 Bool_t merged = kTRUE;
1382 while((str=(TObjString*)next())) {
1383 output_file = str->GetString();
1384 Int_t index = output_file.Index("@");
1385 if (index > 0) output_file.Remove(index);
1386 // Skip already merged outputs
1387 if (!gSystem->AccessPathName(output_file)) {
1388 Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1391 if (fMergeExcludes.Length() &&
1392 fMergeExcludes.Contains(output_file.Data())) continue;
1393 // Perform a 'find' command in the output directory, looking for registered outputs
1394 command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1395 printf("command: %s\n", command.Data());
1396 TGridResult *res = gGrid->Command(command);
1398 TFileMerger *fm = 0;
1401 previous_chunk = "";
1403 // Check if there is a merge operation to resume
1404 output_chunk = output_file;
1405 output_chunk.ReplaceAll(".root", "_*.root");
1406 if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1408 for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1410 Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1414 output_chunk = output_file;
1415 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1416 printf("%s\n", output_chunk.Data());
1418 if (gSystem->AccessPathName(output_chunk)) continue;
1419 // Merged file with chunks up to <count_chunk> found
1420 printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1421 previous_chunk = output_chunk;
1425 count_zero = fMaxMergeFiles;
1426 while ((map=(TMap*)nextmap())) {
1427 // Loop 'find' results and get next LFN
1428 if (count_zero == fMaxMergeFiles) {
1429 // First file in chunk - create file merger and add previous chunk if any.
1430 fm = new TFileMerger(kFALSE);
1431 fm->SetFastMethod(kTRUE);
1432 if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1433 output_chunk = output_file;
1434 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1436 // If last file found, put merged results in the output file
1437 if (map == res->Last()) output_chunk = output_file;
1438 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1439 if (!objs || !objs->GetString().Length()) {
1440 // Nothing found - skip this output
1445 // Add file to be merged and decrement chunk counter.
1446 fm->AddFile(objs->GetString());
1448 if (count_zero==0 || map == res->Last()) {
1449 fm->OutputFile(output_chunk);
1450 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1451 // Nothing found - skip this output
1452 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1457 // Merge the outputs, then go to next chunk
1459 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1465 Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1466 gSystem->Unlink(previous_chunk);
1468 if (map == res->Last()) {
1474 count_zero = fMaxMergeFiles;
1475 previous_chunk = output_chunk;
1480 Error("MergeOutputs", "Terminate() will NOT be executed");
1485 //______________________________________________________________________________
1486 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1488 // Use the output files connected to output containers from the analysis manager
1489 // rather than the files defined by SetOutputFiles
1490 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1491 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1493 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1496 //______________________________________________________________________________
1497 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1499 // Start remote grid analysis.
1501 // Check if output files have to be taken from the analysis manager
1502 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1503 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1504 if (!mgr || !mgr->IsInitialized()) {
1505 Error("StartAnalysis", "You need an initialized analysis manager for this");
1509 TIter next(mgr->GetOutputs());
1510 AliAnalysisDataContainer *output;
1511 while ((output=(AliAnalysisDataContainer*)next())) {
1512 const char *filename = output->GetFileName();
1513 if (!(strcmp(filename, "default"))) {
1514 if (!mgr->GetOutputEventHandler()) continue;
1515 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1517 if (fOutputFiles.Contains(filename)) continue;
1518 if (fOutputFiles.Length()) fOutputFiles += " ";
1519 fOutputFiles += filename;
1521 // Add extra files registered to the analysis manager
1522 if (mgr->GetExtraFiles().Length()) {
1523 if (fOutputFiles.Length()) fOutputFiles += " ";
1524 fOutputFiles += mgr->GetExtraFiles();
1527 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1528 if (TestBit(AliAnalysisGrid::kOffline)) {
1529 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1530 \n there nor any job run. You can revise the JDL and analysis \
1531 \n macro then run the same in \"submit\" mode.");
1532 } else if (TestBit(AliAnalysisGrid::kTest)) {
1533 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1535 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1536 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1537 \n space and job submitted.");
1538 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1539 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1542 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1546 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1550 if (!CheckInputData()) {
1551 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1554 CreateDataset(fDataPattern);
1555 WriteAnalysisFile();
1556 WriteAnalysisMacro();
1558 WriteValidationScript();
1559 if (!CreateJDL()) return kFALSE;
1560 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1561 if (TestBit(AliAnalysisGrid::kTest)) {
1562 // Locally testing the analysis
1563 Info("StartAnalysis", "\n_______________________________________________________________________ \
1564 \n Running analysis script in a daughter shell as on a worker node \
1565 \n_______________________________________________________________________");
1566 TObjArray *list = fOutputFiles.Tokenize(" ");
1569 TString output_file;
1570 while((str=(TObjString*)next())) {
1571 output_file = str->GetString();
1572 Int_t index = output_file.Index("@");
1573 if (index > 0) output_file.Remove(index);
1574 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1577 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1578 TString validationScript = fExecutable;
1579 validationScript.ReplaceAll(".sh", "_validation.sh");
1580 gSystem->Exec(Form("bash %s",validationScript.Data()));
1581 // gSystem->Exec("cat stdout");
1584 // Check if submitting is managed by LPM manager
1585 if (fProductionMode) {
1586 TString prodfile = fJDLName;
1587 prodfile.ReplaceAll(".jdl", ".prod");
1588 WriteProductionFile(prodfile);
1589 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1592 // Submit AliEn job(s)
1593 gGrid->Cd(fGridOutputDir);
1596 if (!fRunNumbers.Length() && !fRunRange[0]) {
1597 // Submit a given xml or a set of runs
1598 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1599 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1601 const char *cjobId = res->GetKey(0,"jobId");
1603 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1606 Info("StartAnalysis", "\n_______________________________________________________________________ \
1607 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1608 \n_______________________________________________________________________",
1609 fJDLName.Data(), cjobId);
1615 // Submit for a range of enumeration of runs.
1619 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1620 \n You may exit at any time and terminate the job later using the option <terminate> \
1621 \n ##################################################################################", jobID.Data());
1622 gSystem->Exec("aliensh");
1626 //______________________________________________________________________________
1627 void AliAnalysisAlien::Submit()
1629 // Submit all master jobs.
1630 Int_t nmasterjobs = fInputFiles->GetEntries();
1631 Long_t tshoot = gSystem->Now();
1632 if (!fNsubmitted) SubmitNext();
1633 while (fNsubmitted < nmasterjobs) {
1634 Long_t now = gSystem->Now();
1635 if ((now-tshoot)>30000) {
1642 //______________________________________________________________________________
1643 void AliAnalysisAlien::SubmitNext()
1645 // Submit next bunch of master jobs if the queue is free.
1646 static Bool_t iscalled = kFALSE;
1647 static Int_t firstmaster = 0;
1648 static Int_t lastmaster = 0;
1649 static Int_t npermaster = 0;
1650 if (iscalled) return;
1652 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1653 Int_t ntosubmit = 0;
1656 if (!fNsubmitted) ntosubmit = 1;
1658 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1659 printf("=== master %d: %s\n", lastmaster, status.Data());
1660 // If last master not split, just return
1661 if (status != "SPLIT") {iscalled = kFALSE; return;}
1662 // No more than 100 waiting jobs
1663 if (nwaiting>100) {iscalled = kFALSE; return;}
1664 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
1665 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1666 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
1667 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1669 Int_t nmasterjobs = fInputFiles->GetEntries();
1670 for (Int_t i=0; i<ntosubmit; i++) {
1671 // Submit for a range of enumeration of runs.
1672 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1674 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
1675 runOutDir.ReplaceAll(".xml", "");
1677 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
1679 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1680 printf("********* %s\n",query.Data());
1681 res = gGrid->Command(query);
1683 TString cjobId1 = res->GetKey(0,"jobId");
1684 if (!cjobId1.Length()) {
1685 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1689 Info("StartAnalysis", "\n_______________________________________________________________________ \
1690 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1691 \n_______________________________________________________________________",
1692 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1695 lastmaster = cjobId1.Atoi();
1696 if (!firstmaster) firstmaster = lastmaster;
1705 //______________________________________________________________________________
1706 void AliAnalysisAlien::WriteAnalysisFile()
1708 // Write current analysis manager into the file <analysisFile>
1709 TString analysisFile = fExecutable;
1710 analysisFile.ReplaceAll(".sh", ".root");
1711 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1712 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1713 if (!mgr || !mgr->IsInitialized()) {
1714 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1717 // Check analysis type
1719 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1720 handler = (TObject*)mgr->GetInputEventHandler();
1722 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1723 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1725 TDirectory *cdir = gDirectory;
1726 TFile *file = TFile::Open(analysisFile, "RECREATE");
1731 if (cdir) cdir->cd();
1732 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1734 Bool_t copy = kTRUE;
1735 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1738 TString workdir = gGrid->GetHomeDirectory();
1739 workdir += fGridWorkingDir;
1740 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1741 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1742 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1746 //______________________________________________________________________________
1747 void AliAnalysisAlien::WriteAnalysisMacro()
1749 // Write the analysis macro that will steer the analysis in grid mode.
1750 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1752 out.open(fAnalysisMacro.Data(), ios::out);
1754 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1757 TString func = fAnalysisMacro;
1758 TString type = "ESD";
1759 TString comment = "// Analysis using ";
1760 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1761 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1765 if (type!="AOD" && fFriendChainName!="") {
1766 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1769 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1770 else comment += " data";
1771 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1772 func.ReplaceAll(".C", "");
1773 out << "void " << func.Data() << "()" << endl;
1775 out << comment.Data() << endl;
1776 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1777 out << " TStopwatch timer;" << endl;
1778 out << " timer.Start();" << endl << endl;
1779 out << "// load base root libraries" << endl;
1780 out << " gSystem->Load(\"libTree\");" << endl;
1781 out << " gSystem->Load(\"libGeom\");" << endl;
1782 out << " gSystem->Load(\"libVMC\");" << endl;
1783 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
1784 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
1785 out << "// Load analysis framework libraries" << endl;
1787 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1788 out << " gSystem->Load(\"libESD\");" << endl;
1789 out << " gSystem->Load(\"libAOD\");" << endl;
1790 out << " gSystem->Load(\"libANALYSIS\");" << endl;
1791 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1792 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1794 TIter next(fPackages);
1797 Bool_t hasSTEERBase = kFALSE;
1798 Bool_t hasESD = kFALSE;
1799 Bool_t hasAOD = kFALSE;
1800 Bool_t hasANALYSIS = kFALSE;
1801 Bool_t hasANALYSISalice = kFALSE;
1802 Bool_t hasCORRFW = kFALSE;
1803 while ((obj=next())) {
1804 pkgname = obj->GetName();
1805 if (pkgname == "STEERBase" ||
1806 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1807 if (pkgname == "ESD" ||
1808 pkgname == "ESD.par") hasESD = kTRUE;
1809 if (pkgname == "AOD" ||
1810 pkgname == "AOD.par") hasAOD = kTRUE;
1811 if (pkgname == "ANALYSIS" ||
1812 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1813 if (pkgname == "ANALYSISalice" ||
1814 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1815 if (pkgname == "CORRFW" ||
1816 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
1818 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1819 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1820 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1821 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1822 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1823 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1824 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1825 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1826 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1827 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1828 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1829 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1830 out << "// Compile other par packages" << endl;
1832 while ((obj=next())) {
1833 pkgname = obj->GetName();
1834 if (pkgname == "STEERBase" ||
1835 pkgname == "STEERBase.par" ||
1837 pkgname == "ESD.par" ||
1839 pkgname == "AOD.par" ||
1840 pkgname == "ANALYSIS" ||
1841 pkgname == "ANALYSIS.par" ||
1842 pkgname == "ANALYSISalice" ||
1843 pkgname == "ANALYSISalice.par" ||
1844 pkgname == "CORRFW" ||
1845 pkgname == "CORRFW.par") continue;
1846 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1849 out << "// include path" << endl;
1850 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1851 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1852 if (fAdditionalLibs.Length()) {
1853 out << "// Add aditional AliRoot libraries" << endl;
1854 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1857 while((str=(TObjString*)next())) {
1858 if (str->GetString().Contains(".so"))
1859 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1861 if (list) delete list;
1864 out << "// analysis source to be compiled at runtime (if any)" << endl;
1865 if (fAnalysisSource.Length()) {
1866 TObjArray *list = fAnalysisSource.Tokenize(" ");
1869 while((str=(TObjString*)next())) {
1870 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1872 if (list) delete list;
1875 out << "// connect to AliEn and make the chain" << endl;
1876 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1877 if (IsUsingTags()) {
1878 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1880 if(fFriendChainName!="AliAOD.VertexingHF.root") {
1881 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1883 out << " // Check if the macro to create the chain was provided" << endl;
1884 out << " if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1885 out << " ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1886 out << " return;" << endl;
1887 out << " }" << endl;
1888 out << " gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1889 out << " TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1892 out << "// read the analysis manager from file" << endl;
1893 TString analysisFile = fExecutable;
1894 analysisFile.ReplaceAll(".sh", ".root");
1895 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1896 out << " if (!file) return;" << endl;
1897 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1898 out << " AliAnalysisManager *mgr = 0;" << endl;
1899 out << " TKey *key;" << endl;
1900 out << " while ((key=(TKey*)nextkey())) {" << endl;
1901 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1902 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1903 out << " };" << endl;
1904 out << " if (!mgr) {" << endl;
1905 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1906 out << " return;" << endl;
1907 out << " }" << endl << endl;
1908 out << " mgr->PrintStatus();" << endl;
1909 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1910 out << " timer.Stop();" << endl;
1911 out << " timer.Print();" << endl;
1912 out << "}" << endl << endl;
1913 if (IsUsingTags()) {
1914 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1916 out << "// Create a chain using tags from the xml file." << endl;
1917 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1918 out << " if (!coll) {" << endl;
1919 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1920 out << " return NULL;" << endl;
1921 out << " }" << endl;
1922 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1923 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1924 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1925 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1926 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1927 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1928 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1929 out << " // Check if the cuts configuration file was provided" << endl;
1930 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1931 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1932 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1933 out << " }" << endl;
1934 if (fFriendChainName=="") {
1935 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1937 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1938 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1939 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1941 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1942 out << " chain->ls();" << endl;
1943 out << " return chain;" << endl;
1944 out << "}" << endl << endl;
1945 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1946 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1947 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1948 msg += " AliLHCTagCuts *lhcCuts,\n";
1949 msg += " AliDetectorTagCuts *detCuts,\n";
1950 msg += " AliEventTagCuts *evCuts)";
1951 Info("WriteAnalysisMacro", msg.Data());
1954 if (!IsUsingTags() || fFriendChainName!="") {
1955 out <<"//________________________________________________________________________________" << endl;
1956 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1958 out << "// Create a chain using url's from xml file" << endl;
1959 out << " TString treename = type;" << endl;
1960 out << " treename.ToLower();" << endl;
1961 out << " treename += \"Tree\";" << endl;
1962 out << " printf(\"***************************************\\n\");" << endl;
1963 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
1964 out << " printf(\"***************************************\\n\");" << endl;
1965 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1966 out << " if (!coll) {" << endl;
1967 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1968 out << " return NULL;" << endl;
1969 out << " }" << endl;
1970 out << " TChain *chain = new TChain(treename);" << endl;
1971 if(fFriendChainName!="") {
1972 out << " TChain *chainFriend = new TChain(treename);" << endl;
1974 out << " coll->Reset();" << endl;
1975 out << " while (coll->Next()) {" << endl;
1976 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
1977 if(fFriendChainName!="") {
1978 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
1979 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1980 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1981 out << " chainFriend->Add(fileFriend.Data());" << endl;
1983 out << " }" << endl;
1984 out << " if (!chain->GetNtrees()) {" << endl;
1985 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1986 out << " return NULL;" << endl;
1987 out << " }" << endl;
1988 if(fFriendChainName!="") {
1989 out << " chain->AddFriend(chainFriend);" << endl;
1991 out << " return chain;" << endl;
1992 out << "}" << endl << endl;
1995 out <<"//________________________________________________________________________________" << endl;
1996 out << "Bool_t SetupPar(const char *package) {" << endl;
1997 out << "// Compile the package and set it up." << endl;
1998 out << " TString pkgdir = package;" << endl;
1999 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2000 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2001 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2002 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2003 out << " // Check for BUILD.sh and execute" << endl;
2004 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2005 out << " printf(\"*******************************\\n\");" << endl;
2006 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2007 out << " printf(\"*******************************\\n\");" << endl;
2008 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2009 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2010 out << " gSystem->ChangeDirectory(cdir);" << endl;
2011 out << " return kFALSE;" << endl;
2012 out << " }" << endl;
2013 out << " } else {" << endl;
2014 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2015 out << " gSystem->ChangeDirectory(cdir);" << endl;
2016 out << " return kFALSE;" << endl;
2017 out << " }" << endl;
2018 out << " // Check for SETUP.C and execute" << endl;
2019 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2020 out << " printf(\"*******************************\\n\");" << endl;
2021 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2022 out << " printf(\"*******************************\\n\");" << endl;
2023 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2024 out << " } else {" << endl;
2025 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2026 out << " gSystem->ChangeDirectory(cdir);" << endl;
2027 out << " return kFALSE;" << endl;
2028 out << " }" << endl;
2029 out << " // Restore original workdir" << endl;
2030 out << " gSystem->ChangeDirectory(cdir);" << endl;
2031 out << " return kTRUE;" << endl;
2034 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2036 Bool_t copy = kTRUE;
2037 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2040 TString workdir = gGrid->GetHomeDirectory();
2041 workdir += fGridWorkingDir;
2042 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2043 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2044 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2045 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2046 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2048 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2049 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2053 //______________________________________________________________________________
2054 void AliAnalysisAlien::WriteExecutable()
2056 // Generate the alien executable script.
2057 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2059 out.open(fExecutable.Data(), ios::out);
2061 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2064 out << "#!/bin/bash" << endl;
2065 out << "echo \"=========================================\"" << endl;
2066 out << "echo \"############## PATH : ##############\"" << endl;
2067 out << "echo $PATH" << endl;
2068 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2069 out << "echo $LD_LIBRARY_PATH" << endl;
2070 out << "echo \"############## ROOTSYS : ##############\"" << endl;
2071 out << "echo $ROOTSYS" << endl;
2072 out << "echo \"############## which root : ##############\"" << endl;
2073 out << "which root" << endl;
2074 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2075 out << "echo $ALICE_ROOT" << endl;
2076 out << "echo \"############## which aliroot : ##############\"" << endl;
2077 out << "which aliroot" << endl;
2078 out << "echo \"############## system limits : ##############\"" << endl;
2079 out << "ulimit -a" << endl;
2080 out << "echo \"############## memory : ##############\"" << endl;
2081 out << "free -m" << endl;
2082 out << "echo \"=========================================\"" << endl << endl;
2083 // Make sure we can properly compile par files
2084 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2085 out << fExecutableCommand << " ";
2086 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2087 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2088 out << "echo \"############## memory after: ##############\"" << endl;
2089 out << "free -m" << endl;
2090 out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2091 out << "dmesg | tail -n 10" << endl;
2093 Bool_t copy = kTRUE;
2094 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2097 TString workdir = gGrid->GetHomeDirectory();
2098 TString bindir = Form("%s/bin", workdir.Data());
2099 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2100 workdir += fGridWorkingDir;
2101 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2102 if (FileExists(executable)) gGrid->Rm(executable);
2103 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2104 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2108 //______________________________________________________________________________
2109 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2111 // Write the production file to be submitted by LPM manager. The format is:
2112 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2113 // Next lines: full_path_to_dataset XXX (XXX is a string)
2114 // To submit, one has to: submit jdl XXX for all lines
2116 out.open(filename, ios::out);
2118 Error("WriteProductionFile", "Bad file name: %s", filename);
2121 TString workdir = gGrid->GetHomeDirectory();
2122 workdir += fGridWorkingDir;
2123 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2124 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2125 out << locjdl << " " << njobspermaster << endl;
2126 Int_t nmasterjobs = fInputFiles->GetEntries();
2127 for (Int_t i=0; i<nmasterjobs; i++) {
2128 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2130 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
2131 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
2134 //______________________________________________________________________________
2135 void AliAnalysisAlien::WriteValidationScript()
2137 // Generate the alien validation script.
2138 // Generate the validation script
2140 TString validationScript = fExecutable;
2141 validationScript.ReplaceAll(".sh", "_validation.sh");
2143 Error("WriteValidationScript", "Alien connection required");
2146 TString out_stream = "";
2147 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2148 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2150 out.open(validationScript, ios::out);
2151 out << "#!/bin/bash" << endl;
2152 out << "##################################################" << endl;
2153 out << "validateout=`dirname $0`" << endl;
2154 out << "validatetime=`date`" << endl;
2155 out << "validated=\"0\";" << endl;
2156 out << "error=0" << endl;
2157 out << "if [ -z $validateout ]" << endl;
2158 out << "then" << endl;
2159 out << " validateout=\".\"" << endl;
2160 out << "fi" << endl << endl;
2161 out << "cd $validateout;" << endl;
2162 out << "validateworkdir=`pwd`;" << endl << endl;
2163 out << "echo \"*******************************************************\"" << out_stream << endl;
2164 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
2166 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
2167 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
2168 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
2169 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2170 out << "ls -la ./" << out_stream << endl;
2171 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
2172 out << "##################################################" << endl;
2175 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2176 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2177 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2180 out << "if [ ! -f stderr ] ; then" << endl;
2181 out << " error=1" << endl;
2182 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
2183 out << " echo \"Error = $error\" " << out_stream << endl;
2184 out << "fi" << endl;
2186 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2187 out << " error=1" << endl;
2188 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
2189 out << " echo \"$parArch\" " << out_stream << endl;
2190 out << " echo \"Error = $error\" " << out_stream << endl;
2191 out << "fi" << endl;
2193 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2194 out << " error=1" << endl;
2195 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
2196 out << " echo \"$segViol\" " << out_stream << endl;
2197 out << " echo \"Error = $error\" " << out_stream << endl;
2198 out << "fi" << endl;
2200 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2201 out << " error=1" << endl;
2202 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
2203 out << " echo \"$segFault\" " << out_stream << endl;
2204 out << " echo \"Error = $error\" " << out_stream << endl;
2205 out << "fi" << endl;
2207 // Part dedicated to the specific analyses running into the train
2209 TObjArray *arr = fOutputFiles.Tokenize(" ");
2211 TString output_file;
2212 while ((os=(TObjString*)next1())) {
2213 output_file = os->GetString();
2214 Int_t index = output_file.Index("@");
2215 if (index > 0) output_file.Remove(index);
2216 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2217 out << " error=1" << endl;
2218 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
2219 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2220 out << "fi" << endl;
2223 out << "if ! [ -f outputs_valid ] ; then" << endl;
2224 out << " error=1" << endl;
2225 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2226 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2227 out << "fi" << endl;
2229 out << "if [ $error = 0 ] ; then" << endl;
2230 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
2231 out << "fi" << endl;
2233 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2234 out << "echo \"*******************************************************\"" << out_stream << endl;
2235 out << "cd -" << endl;
2236 out << "exit $error" << endl;
2238 Bool_t copy = kTRUE;
2239 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2242 TString workdir = gGrid->GetHomeDirectory();
2243 workdir += fGridWorkingDir;
2244 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
2245 if (FileExists(validationScript)) gGrid->Rm(validationScript);
2246 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));