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),
65 fAdditionalRootLibs(),
96 //______________________________________________________________________________
97 AliAnalysisAlien::AliAnalysisAlien(const char *name)
98 :AliAnalysisGrid(name),
102 fSplitMaxInputFileNumber(0),
104 fMasterResubmitThreshold(0),
113 fExecutableCommand(),
118 fAdditionalRootLibs(),
149 //______________________________________________________________________________
150 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
151 :AliAnalysisGrid(other),
153 fPrice(other.fPrice),
155 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
156 fMaxInitFailed(other.fMaxInitFailed),
157 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
158 fNtestFiles(other.fNtestFiles),
159 fNrunsPerMaster(other.fNrunsPerMaster),
160 fMaxMergeFiles(other.fMaxMergeFiles),
161 fNsubmitted(other.fNsubmitted),
162 fProductionMode(other.fProductionMode),
163 fOutputToRunNo(other.fOutputToRunNo),
164 fRunNumbers(other.fRunNumbers),
165 fExecutable(other.fExecutable),
166 fExecutableCommand(other.fExecutableCommand),
167 fArguments(other.fArguments),
168 fExecutableArgs(other.fExecutableArgs),
169 fAnalysisMacro(other.fAnalysisMacro),
170 fAnalysisSource(other.fAnalysisSource),
171 fAdditionalRootLibs(other.fAdditionalRootLibs),
172 fAdditionalLibs(other.fAdditionalLibs),
173 fSplitMode(other.fSplitMode),
174 fAPIVersion(other.fAPIVersion),
175 fROOTVersion(other.fROOTVersion),
176 fAliROOTVersion(other.fAliROOTVersion),
177 fExternalPackages(other.fExternalPackages),
179 fGridWorkingDir(other.fGridWorkingDir),
180 fGridDataDir(other.fGridDataDir),
181 fDataPattern(other.fDataPattern),
182 fGridOutputDir(other.fGridOutputDir),
183 fOutputArchive(other.fOutputArchive),
184 fOutputFiles(other.fOutputFiles),
185 fInputFormat(other.fInputFormat),
186 fDatasetName(other.fDatasetName),
187 fJDLName(other.fJDLName),
188 fMergeExcludes(other.fMergeExcludes),
189 fIncludePath(other.fIncludePath),
190 fCloseSE(other.fCloseSE),
191 fFriendChainName(other.fFriendChainName),
192 fJobTag(other.fJobTag),
193 fOutputSingle(other.fOutputSingle),
194 fRunPrefix(other.fRunPrefix),
199 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
200 fRunRange[0] = other.fRunRange[0];
201 fRunRange[1] = other.fRunRange[1];
202 if (other.fInputFiles) {
203 fInputFiles = new TObjArray();
204 TIter next(other.fInputFiles);
206 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
207 fInputFiles->SetOwner();
209 if (other.fPackages) {
210 fPackages = new TObjArray();
211 TIter next(other.fPackages);
213 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
214 fPackages->SetOwner();
218 //______________________________________________________________________________
219 AliAnalysisAlien::~AliAnalysisAlien()
222 if (fGridJDL) delete fGridJDL;
223 if (fInputFiles) delete fInputFiles;
224 if (fPackages) delete fPackages;
227 //______________________________________________________________________________
228 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
231 if (this != &other) {
232 AliAnalysisGrid::operator=(other);
233 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
234 fPrice = other.fPrice;
236 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
237 fMaxInitFailed = other.fMaxInitFailed;
238 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
239 fNtestFiles = other.fNtestFiles;
240 fNrunsPerMaster = other.fNrunsPerMaster;
241 fMaxMergeFiles = other.fMaxMergeFiles;
242 fNsubmitted = other.fNsubmitted;
243 fProductionMode = other.fProductionMode;
244 fOutputToRunNo = other.fOutputToRunNo;
245 fRunNumbers = other.fRunNumbers;
246 fExecutable = other.fExecutable;
247 fExecutableCommand = other.fExecutableCommand;
248 fArguments = other.fArguments;
249 fExecutableArgs = other.fExecutableArgs;
250 fAnalysisMacro = other.fAnalysisMacro;
251 fAnalysisSource = other.fAnalysisSource;
252 fAdditionalRootLibs = other.fAdditionalRootLibs;
253 fAdditionalLibs = other.fAdditionalLibs;
254 fSplitMode = other.fSplitMode;
255 fAPIVersion = other.fAPIVersion;
256 fROOTVersion = other.fROOTVersion;
257 fAliROOTVersion = other.fAliROOTVersion;
258 fExternalPackages = other.fExternalPackages;
260 fGridWorkingDir = other.fGridWorkingDir;
261 fGridDataDir = other.fGridDataDir;
262 fDataPattern = other.fDataPattern;
263 fGridOutputDir = other.fGridOutputDir;
264 fOutputArchive = other.fOutputArchive;
265 fOutputFiles = other.fOutputFiles;
266 fInputFormat = other.fInputFormat;
267 fDatasetName = other.fDatasetName;
268 fJDLName = other.fJDLName;
269 fMergeExcludes = other.fMergeExcludes;
270 fIncludePath = other.fIncludePath;
271 fCloseSE = other.fCloseSE;
272 fFriendChainName = other.fFriendChainName;
273 fJobTag = other.fJobTag;
274 fOutputSingle = other.fOutputSingle;
275 fRunPrefix = other.fRunPrefix;
276 if (other.fInputFiles) {
277 fInputFiles = new TObjArray();
278 TIter next(other.fInputFiles);
280 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
281 fInputFiles->SetOwner();
283 if (other.fPackages) {
284 fPackages = new TObjArray();
285 TIter next(other.fPackages);
287 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
288 fPackages->SetOwner();
294 //______________________________________________________________________________
295 void AliAnalysisAlien::AddIncludePath(const char *path)
297 // Add include path in the remote analysis macro.
299 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
300 else fIncludePath += Form("-I%s ", path);
303 //______________________________________________________________________________
304 void AliAnalysisAlien::AddRunNumber(Int_t run)
306 // Add a run number to the list of runs to be processed.
307 if (fRunNumbers.Length()) fRunNumbers += " ";
308 fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
311 //______________________________________________________________________________
312 void AliAnalysisAlien::AddRunNumber(const char* run)
314 // Add a run number to the list of runs to be processed.
315 if (fRunNumbers.Length()) fRunNumbers += " ";
319 //______________________________________________________________________________
320 void AliAnalysisAlien::AddDataFile(const char *lfn)
322 // Adds a data file to the input to be analysed. The file should be a valid LFN
323 // or point to an existing file in the alien workdir.
324 if (!fInputFiles) fInputFiles = new TObjArray();
325 fInputFiles->Add(new TObjString(lfn));
328 //______________________________________________________________________________
329 void AliAnalysisAlien::AddExternalPackage(const char *package)
331 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
332 if (fExternalPackages) fExternalPackages += " ";
333 fExternalPackages += package;
336 //______________________________________________________________________________
337 Bool_t AliAnalysisAlien::Connect()
339 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
340 if (gGrid && gGrid->IsConnected()) return kTRUE;
341 if (!gSystem->Getenv("alien_API_USER")) {
342 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
343 gSystem->Getenv("UID"));
347 Info("Connect", "Trying to connect to AliEn ...");
348 TGrid::Connect("alien://");
350 if (!gGrid || !gGrid->IsConnected()) {
351 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
354 fUser = gGrid->GetUser();
355 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
359 //______________________________________________________________________________
360 void AliAnalysisAlien::CdWork()
362 // Check validity of alien workspace. Create directory if possible.
364 Error("CdWork", "Alien connection required");
367 TString homedir = gGrid->GetHomeDirectory();
368 TString workdir = homedir + fGridWorkingDir;
369 if (DirectoryExists(workdir)) {
373 // Work directory not existing - create it
375 if (gGrid->Mkdir(workdir)) {
376 gGrid->Cd(fGridWorkingDir);
377 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
379 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
380 workdir.Data(), homedir.Data());
381 fGridWorkingDir = "";
385 //______________________________________________________________________________
386 Bool_t AliAnalysisAlien::CheckInputData()
388 // Check validity of input data. If necessary, create xml files.
389 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
390 if (!fGridDataDir.Length()) {
391 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
394 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
397 // Process declared files
398 Bool_t is_collection = kFALSE;
399 Bool_t is_xml = kFALSE;
400 Bool_t use_tags = kFALSE;
401 Bool_t checked = kFALSE;
404 TString workdir = gGrid->GetHomeDirectory();
405 workdir += fGridWorkingDir;
408 TIter next(fInputFiles);
409 while ((objstr=(TObjString*)next())) {
412 file += objstr->GetString();
413 // Store full lfn path
414 if (FileExists(file)) objstr->SetString(file);
416 file = objstr->GetName();
417 if (!FileExists(objstr->GetName())) {
418 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
419 objstr->GetName(), workdir.Data());
423 Bool_t iscoll, isxml, usetags;
424 CheckDataType(file, iscoll, isxml, usetags);
427 is_collection = iscoll;
430 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
432 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
433 Error("CheckInputData", "Some conflict was found in the types of inputs");
439 // Process requested run numbers
440 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
441 // Check validity of alien data directory
442 if (!fGridDataDir.Length()) {
443 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
446 if (!DirectoryExists(fGridDataDir)) {
447 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
451 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
455 if (checked && !is_xml) {
456 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
459 // Check validity of run number(s)
463 TString schunk, schunk2;
467 use_tags = fDataPattern.Contains("tag");
468 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
470 if (use_tags != fDataPattern.Contains("tag")) {
471 Error("CheckInputData", "Cannot mix input files using/not using tags");
474 if (fRunNumbers.Length()) {
475 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
476 arr = fRunNumbers.Tokenize(" ");
478 while ((os=(TObjString*)next())) {
479 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
480 if (!DirectoryExists(path)) {
481 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
484 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
485 TString msg = "\n##### file: ";
487 msg += " type: xml_collection;";
488 if (use_tags) msg += " using_tags: Yes";
489 else msg += " using_tags: No";
490 Info("CheckDataType", msg.Data());
491 if (fNrunsPerMaster<2) {
492 AddDataFile(Form("%s.xml", os->GetString().Data()));
495 if (((nruns-1)%fNrunsPerMaster) == 0) {
496 schunk = os->GetString();
498 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
499 schunk += Form("_%s.xml", os->GetString().Data());
505 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
506 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
507 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
508 if (!DirectoryExists(path)) {
509 // Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
512 path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
513 TString msg = "\n##### file: ";
515 msg += " type: xml_collection;";
516 if (use_tags) msg += " using_tags: Yes";
517 else msg += " using_tags: No";
518 Info("CheckDataType", msg.Data());
519 if (fNrunsPerMaster<2) {
520 AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
523 if (((nruns-1)%fNrunsPerMaster) == 0) {
524 schunk = Form("%s%d", fRunPrefix.Data(),irun);
526 schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
527 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
540 //______________________________________________________________________________
541 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
543 // Create dataset for the grid data directory + run number.
544 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
546 Error("CreateDataset", "Cannot create dataset with no grid connection");
552 TString workdir = gGrid->GetHomeDirectory();
553 workdir += fGridWorkingDir;
555 // Compose the 'find' command arguments
557 TString options = "-x collection ";
558 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
559 TString conditions = "";
564 TString schunk, schunk2;
565 TGridCollection *cbase=0, *cadd=0;
566 if (!fRunNumbers.Length() && !fRunRange[0]) {
567 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
568 // Make a single data collection from data directory.
570 if (!DirectoryExists(path)) {
571 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
575 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
576 else file = Form("%s.xml", gSystem->BaseName(path));
577 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest)) {
583 command += conditions;
584 printf("command: %s\n", command.Data());
585 TGridResult *res = gGrid->Command(command);
587 // Write standard output to file
588 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
590 if (!TestBit(AliAnalysisGrid::kTest) && !FileExists(file)) {
591 // Copy xml file to alien space
592 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
593 if (!FileExists(file)) {
594 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
597 // Update list of files to be processed.
599 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
603 if (fRunNumbers.Length()) {
604 TObjArray *arr = fRunNumbers.Tokenize(" ");
607 while ((os=(TObjString*)next())) {
608 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
609 if (!DirectoryExists(path)) continue;
611 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
612 else file = Form("%s.xml", os->GetString().Data());
613 // If local collection file does not exist, create it via 'find' command.
614 if (gSystem->AccessPathName(file)) {
619 command += conditions;
620 TGridResult *res = gGrid->Command(command);
622 // Write standard output to file
623 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
625 if (TestBit(AliAnalysisGrid::kTest)) break;
626 // Check if there is one run per master job.
627 if (fNrunsPerMaster<2) {
628 if (FileExists(file)) {
629 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
632 // Copy xml file to alien space
633 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
634 if (!FileExists(file)) {
635 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
641 if (((nruns-1)%fNrunsPerMaster) == 0) {
642 schunk = os->GetString();
643 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
645 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
646 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
650 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
653 schunk += Form("_%s.xml", os->GetString().Data());
654 if (FileExists(schunk)) {
655 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
658 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
659 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
660 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
661 if (!FileExists(schunk)) {
662 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
670 // Process a full run range.
671 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
672 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
673 if (!DirectoryExists(path)) continue;
675 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
676 else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
677 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
678 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
682 // If local collection file does not exist, create it via 'find' command.
683 if (gSystem->AccessPathName(file)) {
688 command += conditions;
689 TGridResult *res = gGrid->Command(command);
691 // Write standard output to file
692 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
694 if (TestBit(AliAnalysisGrid::kTest)) break;
695 // Check if there is one run per master job.
696 if (fNrunsPerMaster<2) {
697 if (FileExists(file)) {
698 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
701 // Copy xml file to alien space
702 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
703 if (!FileExists(file)) {
704 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
709 // Check if the collection for the chunk exist locally.
710 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
711 if (FileExists(fInputFiles->At(nchunk)->GetName())) continue;
712 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
713 if (((nruns-1)%fNrunsPerMaster) == 0) {
714 schunk = Form("%s%d", fRunPrefix.Data(), irun);
715 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
717 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
721 schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
722 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
726 if (FileExists(schunk)) {
727 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
730 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
731 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
732 if (FileExists(schunk)) {
733 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
736 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
737 if (!FileExists(schunk)) {
738 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
747 //______________________________________________________________________________
748 Bool_t AliAnalysisAlien::CreateJDL()
750 // Generate a JDL file according to current settings. The name of the file is
751 // specified by fJDLName.
752 Bool_t error = kFALSE;
755 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
756 Bool_t generate = kTRUE;
757 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
759 Error("CreateJDL", "Alien connection required");
762 // Check validity of alien workspace
764 TString workdir = gGrid->GetHomeDirectory();
765 workdir += fGridWorkingDir;
769 Error("CreateJDL()", "Define some input files for your analysis.");
772 // Compose list of input files
773 // Check if output files were defined
774 if (!fOutputFiles.Length()) {
775 Error("CreateJDL", "You must define at least one output file");
778 // Check if an output directory was defined and valid
779 if (!fGridOutputDir.Length()) {
780 Error("CreateJDL", "You must define AliEn output directory");
783 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
784 if (!DirectoryExists(fGridOutputDir)) {
785 if (gGrid->Mkdir(fGridOutputDir)) {
786 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
788 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
794 // Exit if any error up to now
795 if (error) return kFALSE;
797 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
798 fGridJDL->SetExecutable(fExecutable);
799 if (!fArguments.IsNull())
800 fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
801 // fGridJDL->SetTTL((UInt_t)fTTL);
802 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
803 if (fMaxInitFailed > 0)
804 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
805 if (fSplitMaxInputFileNumber > 0)
806 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
807 if (fSplitMode.Length())
808 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
809 // fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
810 if (fAliROOTVersion.Length())
811 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
812 if (fROOTVersion.Length())
813 fGridJDL->AddToPackages("ROOT", fROOTVersion);
814 if (fAPIVersion.Length())
815 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
816 if (!fExternalPackages.IsNull()) {
817 arr = fExternalPackages.Tokenize(" ");
819 while ((os=(TObjString*)next())) {
820 TString pkgname = os->GetString();
821 Int_t index = pkgname.Index("::");
822 TString pkgversion = pkgname(index+2, pkgname.Length());
823 pkgname.Remove(index);
824 fGridJDL->AddToPackages(pkgname, pkgversion);
828 fGridJDL->SetInputDataListFormat(fInputFormat);
829 fGridJDL->SetInputDataList("wn.xml");
830 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
831 TString analysisFile = fExecutable;
832 analysisFile.ReplaceAll(".sh", ".root");
833 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
834 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
835 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
836 if (fAdditionalLibs.Length()) {
837 arr = fAdditionalLibs.Tokenize(" ");
839 while ((os=(TObjString*)next())) {
840 if (os->GetString().Contains(".so")) continue;
841 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
846 TIter next(fPackages);
849 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
851 if (fOutputArchive.Length()) {
852 arr = fOutputArchive.Tokenize(" ");
854 while ((os=(TObjString*)next()))
855 if (!os->GetString().Contains("@") && fCloseSE.Length())
856 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
858 fGridJDL->AddToOutputArchive(os->GetString());
861 arr = fOutputFiles.Tokenize(" ");
863 while ((os=(TObjString*)next())) {
864 // Ignore ouputs in jdl that are also in outputarchive
865 TString sout = os->GetString();
866 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
867 if (fOutputArchive.Contains(sout)) continue;
868 if (!os->GetString().Contains("@") && fCloseSE.Length())
869 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
871 fGridJDL->AddToOutputSandbox(os->GetString());
874 // fGridJDL->SetPrice((UInt_t)fPrice);
875 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
876 TString validationScript = fExecutable;
877 validationScript.ReplaceAll(".sh", "_validation.sh");
878 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()));
879 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
880 // Write a jdl with 2 input parameters: collection name and output dir name.
883 // Copy jdl to grid workspace
885 // Check if an output directory was defined and valid
886 if (!fGridOutputDir.Length()) {
887 Error("CreateJDL", "You must define AliEn output directory");
890 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
891 if (!DirectoryExists(fGridOutputDir)) {
892 if (gGrid->Mkdir(fGridOutputDir)) {
893 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
895 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
901 if (TestBit(AliAnalysisGrid::kSubmit)) {
902 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
903 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
905 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
906 if (FileExists(locjdl)) gGrid->Rm(locjdl);
907 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
909 if (fAdditionalLibs.Length()) {
910 arr = fAdditionalLibs.Tokenize(" ");
913 while ((os=(TObjString*)next())) {
914 if (os->GetString().Contains(".so")) continue;
915 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
916 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
917 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
922 TIter next(fPackages);
924 while ((obj=next())) {
925 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
926 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
933 //______________________________________________________________________________
934 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
936 // Writes one or more JDL's corresponding to findex. If findex is negative,
937 // all run numbers are considered in one go (jdl). For non-negative indices
938 // they correspond to the indices in the array fInputFiles.
939 if (!fInputFiles) return kFALSE;
941 TString workdir = gGrid->GetHomeDirectory();
942 workdir += fGridWorkingDir;
944 if (!fRunNumbers.Length() && !fRunRange[0]) {
945 // One jdl with no parameters in case input data is specified by name.
946 TIter next(fInputFiles);
947 while ((os=(TObjString*)next()))
948 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
949 if (!fOutputSingle.IsNull())
950 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
952 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
954 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
955 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
956 if (!fOutputSingle.IsNull()) {
957 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
958 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()));
960 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
965 // Generate the JDL as a string
966 TString sjdl = fGridJDL->Generate();
968 index = sjdl.Index("Executable");
969 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
970 index = sjdl.Index("Split ");
971 if (index >= 0) sjdl.Insert(index, "\n# We split per SE or file\n");
972 index = sjdl.Index("SplitMaxInputFileNumber");
973 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
974 index = sjdl.Index("InputDataCollection");
975 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
976 index = sjdl.Index("InputFile");
977 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
978 index = sjdl.Index("InputDataList ");
979 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
980 index = sjdl.Index("InputDataListFormat");
981 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
982 index = sjdl.Index("Price");
983 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
984 index = sjdl.Index("Requirements");
985 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
986 index = sjdl.Index("Packages");
987 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
988 index = sjdl.Index("User =");
989 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
990 index = sjdl.Index("TTL");
991 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
992 index = sjdl.Index("OutputFile");
993 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
994 index = sjdl.Index("OutputDir");
995 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
996 index = sjdl.Index("OutputArchive");
997 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
998 index = sjdl.Index("MaxInitFailed");
999 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
1000 index = sjdl.Index("MasterResubmitThreshold");
1001 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
1002 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
1003 index = sjdl.Index("Validationcommand");
1004 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
1005 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1006 sjdl.ReplaceAll("(member", "\n (member");
1007 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1008 sjdl.ReplaceAll("{", "{\n ");
1009 sjdl.ReplaceAll("};", "\n};");
1010 sjdl.ReplaceAll("{\n \n", "{\n");
1011 sjdl.ReplaceAll("\n\n", "\n");
1012 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1013 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1014 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
1015 index = sjdl.Index("JDLVariables");
1016 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1017 // Write jdl to file
1019 out.open(fJDLName.Data(), ios::out);
1021 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1024 out << sjdl << endl;
1026 // Copy jdl to grid workspace
1028 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1030 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1031 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1032 if (fProductionMode)
1033 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1034 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1035 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1040 //______________________________________________________________________________
1041 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1043 // Returns true if file exists.
1044 if (!gGrid) return kFALSE;
1045 TGridResult *res = gGrid->Ls(lfn);
1046 if (!res) return kFALSE;
1047 TMap *map = dynamic_cast<TMap*>(res->At(0));
1052 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1053 if (!objs || !objs->GetString().Length()) {
1061 //______________________________________________________________________________
1062 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1064 // Returns true if directory exists. Can be also a path.
1065 if (!gGrid) return kFALSE;
1066 // Check if dirname is a path
1067 TString dirstripped = dirname;
1068 dirstripped = dirstripped.Strip();
1069 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1070 TString dir = gSystem->BaseName(dirstripped);
1072 TString path = gSystem->DirName(dirstripped);
1073 TGridResult *res = gGrid->Ls(path, "-F");
1074 if (!res) return kFALSE;
1078 while ((map=dynamic_cast<TMap*>(next()))) {
1079 obj = map->GetValue("name");
1081 if (dir == obj->GetName()) {
1090 //______________________________________________________________________________
1091 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1093 // Check input data type.
1094 is_collection = kFALSE;
1098 Error("CheckDataType", "No connection to grid");
1101 is_collection = IsCollection(lfn);
1102 TString msg = "\n##### file: ";
1104 if (is_collection) {
1105 msg += " type: raw_collection;";
1106 // special treatment for collections
1108 // check for tag files in the collection
1109 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1111 msg += " using_tags: No (unknown)";
1112 Info("CheckDataType", msg.Data());
1115 const char* typeStr = res->GetKey(0, "origLFN");
1116 if (!typeStr || !strlen(typeStr)) {
1117 msg += " using_tags: No (unknown)";
1118 Info("CheckDataType", msg.Data());
1121 TString file = typeStr;
1122 use_tags = file.Contains(".tag");
1123 if (use_tags) msg += " using_tags: Yes";
1124 else msg += " using_tags: No";
1125 Info("CheckDataType", msg.Data());
1130 is_xml = slfn.Contains(".xml");
1132 // Open xml collection and check if there are tag files inside
1133 msg += " type: xml_collection;";
1134 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1136 msg += " using_tags: No (unknown)";
1137 Info("CheckDataType", msg.Data());
1140 TMap *map = coll->Next();
1142 msg += " using_tags: No (unknown)";
1143 Info("CheckDataType", msg.Data());
1146 map = (TMap*)map->GetValue("");
1148 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1149 use_tags = file.Contains(".tag");
1151 if (use_tags) msg += " using_tags: Yes";
1152 else msg += " using_tags: No";
1153 Info("CheckDataType", msg.Data());
1156 use_tags = slfn.Contains(".tag");
1157 if (slfn.Contains(".root")) msg += " type: root file;";
1158 else msg += " type: unhnown file;";
1159 if (use_tags) msg += " using_tags: Yes";
1160 else msg += " using_tags: No";
1161 Info("CheckDataType", msg.Data());
1164 //______________________________________________________________________________
1165 void AliAnalysisAlien::EnablePackage(const char *package)
1167 // Enables a par file supposed to exist in the current directory.
1168 TString pkg(package);
1169 pkg.ReplaceAll(".par", "");
1171 if (gSystem->AccessPathName(pkg)) {
1172 Error("EnablePackage", "Package %s not found", pkg.Data());
1175 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1176 Info("EnablePackage", "AliEn plugin will use .par packages");
1177 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1179 fPackages = new TObjArray();
1180 fPackages->SetOwner();
1182 fPackages->Add(new TObjString(pkg));
1185 //______________________________________________________________________________
1186 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1188 // Get job status for all jobs with jobid>jobidstart.
1189 static char mstatus[20];
1195 TGridJobStatusList *list = gGrid->Ps("");
1196 if (!list) return mstatus;
1197 Int_t nentries = list->GetSize();
1198 TGridJobStatus *status;
1200 for (Int_t ijob=0; ijob<nentries; ijob++) {
1201 status = (TGridJobStatus *)list->At(ijob);
1202 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1203 if (pid<jobidstart) continue;
1204 if (pid == lastid) {
1205 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1207 switch (status->GetStatus()) {
1208 case TGridJobStatus::kWAITING:
1210 case TGridJobStatus::kRUNNING:
1212 case TGridJobStatus::kABORTED:
1213 case TGridJobStatus::kFAIL:
1214 case TGridJobStatus::kUNKNOWN:
1216 case TGridJobStatus::kDONE:
1225 //______________________________________________________________________________
1226 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1228 // Returns true if file is a collection. Functionality duplicated from
1229 // TAlien::Type() because we don't want to directly depend on TAlien.
1231 Error("IsCollection", "No connection to grid");
1234 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1235 if (!res) return kFALSE;
1236 const char* typeStr = res->GetKey(0, "type");
1237 if (!typeStr || !strlen(typeStr)) return kFALSE;
1238 if (!strcmp(typeStr, "collection")) return kTRUE;
1243 //______________________________________________________________________________
1244 Bool_t AliAnalysisAlien::IsSingleOutput() const
1246 // Check if single-ouput option is on.
1247 return (!fOutputSingle.IsNull());
1250 //______________________________________________________________________________
1251 void AliAnalysisAlien::Print(Option_t *) const
1253 // Print current plugin settings.
1254 printf("### AliEn analysis plugin current settings ###\n");
1255 printf("= Production mode:______________________________ %d\n", fProductionMode);
1256 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1257 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1258 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1260 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1261 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1262 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1263 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1264 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1265 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1266 if (fRunNumbers.Length())
1267 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1269 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1270 if (!fRunRange[0] && !fRunNumbers.Length()) {
1271 TIter next(fInputFiles);
1274 while ((obj=next())) list += obj->GetName();
1275 printf("= Input files to be processed: _________________ %s\n", list.Data());
1277 if (TestBit(AliAnalysisGrid::kTest))
1278 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1279 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1280 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1281 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1282 printf("=====================================================================\n");
1283 printf("= Job price: ___________________________________ %d\n", fPrice);
1284 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1285 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1286 if (fMaxInitFailed>0)
1287 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1288 if (fMasterResubmitThreshold>0)
1289 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1290 if (fNrunsPerMaster>0)
1291 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1292 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1293 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1294 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
1295 if (fArguments.Length())
1296 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1297 if (fExecutableArgs.Length())
1298 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1299 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1300 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1301 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1302 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1304 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1305 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1306 if (fIncludePath.Data())
1307 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1308 if (fCloseSE.Length())
1309 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1310 if (fFriendChainName.Length())
1311 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1313 TIter next(fPackages);
1316 while ((obj=next())) list += obj->GetName();
1317 printf("= Par files to be used: ________________________ %s\n", list.Data());
1321 //______________________________________________________________________________
1322 void AliAnalysisAlien::SetDefaults()
1324 // Set default values for everything. What cannot be filled will be left empty.
1325 if (fGridJDL) delete fGridJDL;
1326 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1329 fSplitMaxInputFileNumber = 100;
1331 fMasterResubmitThreshold = 0;
1335 fNrunsPerMaster = 1;
1336 fMaxMergeFiles = 100;
1338 fExecutable = "analysis.sh";
1339 fExecutableCommand = "root -b -q";
1341 fExecutableArgs = "";
1342 fAnalysisMacro = "myAnalysis.C";
1343 fAnalysisSource = "";
1344 fAdditionalLibs = "";
1348 fAliROOTVersion = "";
1349 fUser = ""; // Your alien user name
1350 fGridWorkingDir = "";
1351 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1352 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1353 fFriendChainName = "";
1354 fGridOutputDir = "output";
1355 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1356 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1357 fInputFormat = "xml-single";
1358 fJDLName = "analysis.jdl";
1359 fJobTag = "Automatically generated analysis JDL";
1360 fMergeExcludes = "";
1363 //______________________________________________________________________________
1364 Bool_t AliAnalysisAlien::MergeOutputs()
1366 // Merge analysis outputs existing in the AliEn space.
1367 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1368 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1370 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1373 // Get the output path
1374 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1375 if (!DirectoryExists(fGridOutputDir)) {
1376 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1379 if (!fOutputFiles.Length()) {
1380 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1383 TObjArray *list = fOutputFiles.Tokenize(" ");
1387 TString output_file;
1388 TString output_chunk;
1389 TString previous_chunk;
1390 Int_t count_chunk = 0;
1391 Int_t count_zero = fMaxMergeFiles;
1392 Bool_t merged = kTRUE;
1393 while((str=(TObjString*)next())) {
1394 output_file = str->GetString();
1395 Int_t index = output_file.Index("@");
1396 if (index > 0) output_file.Remove(index);
1397 // Skip already merged outputs
1398 if (!gSystem->AccessPathName(output_file)) {
1399 Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1402 if (fMergeExcludes.Length() &&
1403 fMergeExcludes.Contains(output_file.Data())) continue;
1404 // Perform a 'find' command in the output directory, looking for registered outputs
1405 command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1406 printf("command: %s\n", command.Data());
1407 TGridResult *res = gGrid->Command(command);
1409 TFileMerger *fm = 0;
1412 previous_chunk = "";
1414 // Check if there is a merge operation to resume
1415 output_chunk = output_file;
1416 output_chunk.ReplaceAll(".root", "_*.root");
1417 if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1419 for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1421 Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1425 output_chunk = output_file;
1426 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1427 printf("%s\n", output_chunk.Data());
1429 if (gSystem->AccessPathName(output_chunk)) continue;
1430 // Merged file with chunks up to <count_chunk> found
1431 printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1432 previous_chunk = output_chunk;
1436 count_zero = fMaxMergeFiles;
1437 while ((map=(TMap*)nextmap())) {
1438 // Loop 'find' results and get next LFN
1439 if (count_zero == fMaxMergeFiles) {
1440 // First file in chunk - create file merger and add previous chunk if any.
1441 fm = new TFileMerger(kFALSE);
1442 fm->SetFastMethod(kTRUE);
1443 if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1444 output_chunk = output_file;
1445 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1447 // If last file found, put merged results in the output file
1448 if (map == res->Last()) output_chunk = output_file;
1449 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1450 if (!objs || !objs->GetString().Length()) {
1451 // Nothing found - skip this output
1456 // Add file to be merged and decrement chunk counter.
1457 fm->AddFile(objs->GetString());
1459 if (count_zero==0 || map == res->Last()) {
1460 fm->OutputFile(output_chunk);
1461 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1462 // Nothing found - skip this output
1463 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1468 // Merge the outputs, then go to next chunk
1470 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1476 Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1477 gSystem->Unlink(previous_chunk);
1479 if (map == res->Last()) {
1485 count_zero = fMaxMergeFiles;
1486 previous_chunk = output_chunk;
1491 Error("MergeOutputs", "Terminate() will NOT be executed");
1496 //______________________________________________________________________________
1497 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1499 // Use the output files connected to output containers from the analysis manager
1500 // rather than the files defined by SetOutputFiles
1501 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1502 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1504 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1507 //______________________________________________________________________________
1508 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1510 // Start remote grid analysis.
1512 // Check if output files have to be taken from the analysis manager
1513 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1514 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1515 if (!mgr || !mgr->IsInitialized()) {
1516 Error("StartAnalysis", "You need an initialized analysis manager for this");
1520 TIter next(mgr->GetOutputs());
1521 AliAnalysisDataContainer *output;
1522 while ((output=(AliAnalysisDataContainer*)next())) {
1523 const char *filename = output->GetFileName();
1524 if (!(strcmp(filename, "default"))) {
1525 if (!mgr->GetOutputEventHandler()) continue;
1526 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1528 if (fOutputFiles.Contains(filename)) continue;
1529 if (fOutputFiles.Length()) fOutputFiles += " ";
1530 fOutputFiles += filename;
1532 // Add extra files registered to the analysis manager
1533 if (mgr->GetExtraFiles().Length()) {
1534 if (fOutputFiles.Length()) fOutputFiles += " ";
1535 fOutputFiles += mgr->GetExtraFiles();
1538 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1539 if (TestBit(AliAnalysisGrid::kOffline)) {
1540 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1541 \n there nor any job run. You can revise the JDL and analysis \
1542 \n macro then run the same in \"submit\" mode.");
1543 } else if (TestBit(AliAnalysisGrid::kTest)) {
1544 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1546 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1547 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1548 \n space and job submitted.");
1549 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1550 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1553 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1557 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1561 if (!CheckInputData()) {
1562 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1565 CreateDataset(fDataPattern);
1566 WriteAnalysisFile();
1567 WriteAnalysisMacro();
1569 WriteValidationScript();
1570 if (!CreateJDL()) return kFALSE;
1571 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1572 if (TestBit(AliAnalysisGrid::kTest)) {
1573 // Locally testing the analysis
1574 Info("StartAnalysis", "\n_______________________________________________________________________ \
1575 \n Running analysis script in a daughter shell as on a worker node \
1576 \n_______________________________________________________________________");
1577 TObjArray *list = fOutputFiles.Tokenize(" ");
1580 TString output_file;
1581 while((str=(TObjString*)next())) {
1582 output_file = str->GetString();
1583 Int_t index = output_file.Index("@");
1584 if (index > 0) output_file.Remove(index);
1585 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1588 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1589 TString validationScript = fExecutable;
1590 validationScript.ReplaceAll(".sh", "_validation.sh");
1591 gSystem->Exec(Form("bash %s",validationScript.Data()));
1592 // gSystem->Exec("cat stdout");
1595 // Check if submitting is managed by LPM manager
1596 if (fProductionMode) {
1597 TString prodfile = fJDLName;
1598 prodfile.ReplaceAll(".jdl", ".prod");
1599 WriteProductionFile(prodfile);
1600 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1603 // Submit AliEn job(s)
1604 gGrid->Cd(fGridOutputDir);
1607 if (!fRunNumbers.Length() && !fRunRange[0]) {
1608 // Submit a given xml or a set of runs
1609 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1610 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1612 const char *cjobId = res->GetKey(0,"jobId");
1614 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1617 Info("StartAnalysis", "\n_______________________________________________________________________ \
1618 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1619 \n_______________________________________________________________________",
1620 fJDLName.Data(), cjobId);
1626 // Submit for a range of enumeration of runs.
1630 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1631 \n You may exit at any time and terminate the job later using the option <terminate> \
1632 \n ##################################################################################", jobID.Data());
1633 gSystem->Exec("aliensh");
1637 //______________________________________________________________________________
1638 void AliAnalysisAlien::Submit()
1640 // Submit all master jobs.
1641 Int_t nmasterjobs = fInputFiles->GetEntries();
1642 Long_t tshoot = gSystem->Now();
1643 if (!fNsubmitted) SubmitNext();
1644 while (fNsubmitted < nmasterjobs) {
1645 Long_t now = gSystem->Now();
1646 if ((now-tshoot)>30000) {
1653 //______________________________________________________________________________
1654 void AliAnalysisAlien::SubmitNext()
1656 // Submit next bunch of master jobs if the queue is free.
1657 static Bool_t iscalled = kFALSE;
1658 static Int_t firstmaster = 0;
1659 static Int_t lastmaster = 0;
1660 static Int_t npermaster = 0;
1661 if (iscalled) return;
1663 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1664 Int_t ntosubmit = 0;
1667 if (!fNsubmitted) ntosubmit = 1;
1669 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1670 printf("=== master %d: %s\n", lastmaster, status.Data());
1671 // If last master not split, just return
1672 if (status != "SPLIT") {iscalled = kFALSE; return;}
1673 // No more than 100 waiting jobs
1674 if (nwaiting>100) {iscalled = kFALSE; return;}
1675 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
1676 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1677 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
1678 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1680 Int_t nmasterjobs = fInputFiles->GetEntries();
1681 for (Int_t i=0; i<ntosubmit; i++) {
1682 // Submit for a range of enumeration of runs.
1683 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1685 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
1686 runOutDir.ReplaceAll(".xml", "");
1688 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
1690 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1691 printf("********* %s\n",query.Data());
1692 res = gGrid->Command(query);
1694 TString cjobId1 = res->GetKey(0,"jobId");
1695 if (!cjobId1.Length()) {
1696 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1700 Info("StartAnalysis", "\n_______________________________________________________________________ \
1701 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1702 \n_______________________________________________________________________",
1703 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1706 lastmaster = cjobId1.Atoi();
1707 if (!firstmaster) firstmaster = lastmaster;
1716 //______________________________________________________________________________
1717 void AliAnalysisAlien::WriteAnalysisFile()
1719 // Write current analysis manager into the file <analysisFile>
1720 TString analysisFile = fExecutable;
1721 analysisFile.ReplaceAll(".sh", ".root");
1722 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1723 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1724 if (!mgr || !mgr->IsInitialized()) {
1725 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1728 // Check analysis type
1730 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1731 handler = (TObject*)mgr->GetInputEventHandler();
1733 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1734 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1736 TDirectory *cdir = gDirectory;
1737 TFile *file = TFile::Open(analysisFile, "RECREATE");
1739 // Skip task Terminate calls for the grid job
1740 mgr->SetSkipTerminate(kTRUE);
1741 // Unless merging makes no sense
1742 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
1745 // Enable termination for local jobs
1746 mgr->SetSkipTerminate(kFALSE);
1748 if (cdir) cdir->cd();
1749 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1751 Bool_t copy = kTRUE;
1752 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1755 TString workdir = gGrid->GetHomeDirectory();
1756 workdir += fGridWorkingDir;
1757 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1758 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1759 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1763 //______________________________________________________________________________
1764 void AliAnalysisAlien::WriteAnalysisMacro()
1766 // Write the analysis macro that will steer the analysis in grid mode.
1767 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1769 out.open(fAnalysisMacro.Data(), ios::out);
1771 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1774 TString func = fAnalysisMacro;
1775 TString type = "ESD";
1776 TString comment = "// Analysis using ";
1777 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1778 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1782 if (type!="AOD" && fFriendChainName!="") {
1783 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1786 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1787 else comment += " data";
1788 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1789 func.ReplaceAll(".C", "");
1790 out << "void " << func.Data() << "()" << endl;
1792 out << comment.Data() << endl;
1793 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1794 out << " TStopwatch timer;" << endl;
1795 out << " timer.Start();" << endl << endl;
1796 out << "// load base root libraries" << endl;
1797 out << " gSystem->Load(\"libTree\");" << endl;
1798 out << " gSystem->Load(\"libGeom\");" << endl;
1799 out << " gSystem->Load(\"libVMC\");" << endl;
1800 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
1801 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
1802 if (fAdditionalRootLibs.Length()) {
1803 // in principle libtree /lib geom libvmc etc. can go into this list, too
1804 out << "// Add aditional libraries" << endl;
1805 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
1808 while((str=(TObjString*)next())) {
1809 if (str->GetString().Contains(".so"))
1810 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1812 if (list) delete list;
1814 out << "// Load analysis framework libraries" << endl;
1818 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1819 out << " gSystem->Load(\"libESD\");" << endl;
1820 out << " gSystem->Load(\"libAOD\");" << endl;
1821 out << " gSystem->Load(\"libANALYSIS\");" << endl;
1822 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1823 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1825 TIter next(fPackages);
1828 Bool_t hasSTEERBase = kFALSE;
1829 Bool_t hasESD = kFALSE;
1830 Bool_t hasAOD = kFALSE;
1831 Bool_t hasANALYSIS = kFALSE;
1832 Bool_t hasANALYSISalice = kFALSE;
1833 Bool_t hasCORRFW = kFALSE;
1834 while ((obj=next())) {
1835 pkgname = obj->GetName();
1836 if (pkgname == "STEERBase" ||
1837 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1838 if (pkgname == "ESD" ||
1839 pkgname == "ESD.par") hasESD = kTRUE;
1840 if (pkgname == "AOD" ||
1841 pkgname == "AOD.par") hasAOD = kTRUE;
1842 if (pkgname == "ANALYSIS" ||
1843 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1844 if (pkgname == "ANALYSISalice" ||
1845 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1846 if (pkgname == "CORRFW" ||
1847 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
1849 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1850 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1851 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1852 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1853 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1854 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1855 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1856 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1857 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1858 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1859 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1860 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1861 out << "// Compile other par packages" << endl;
1863 while ((obj=next())) {
1864 pkgname = obj->GetName();
1865 if (pkgname == "STEERBase" ||
1866 pkgname == "STEERBase.par" ||
1868 pkgname == "ESD.par" ||
1870 pkgname == "AOD.par" ||
1871 pkgname == "ANALYSIS" ||
1872 pkgname == "ANALYSIS.par" ||
1873 pkgname == "ANALYSISalice" ||
1874 pkgname == "ANALYSISalice.par" ||
1875 pkgname == "CORRFW" ||
1876 pkgname == "CORRFW.par") continue;
1877 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1880 out << "// include path" << endl;
1881 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1882 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1883 if (fAdditionalLibs.Length()) {
1884 out << "// Add aditional AliRoot libraries" << endl;
1885 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1888 while((str=(TObjString*)next())) {
1889 if (str->GetString().Contains(".so"))
1890 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1892 if (list) delete list;
1895 out << "// analysis source to be compiled at runtime (if any)" << endl;
1896 if (fAnalysisSource.Length()) {
1897 TObjArray *list = fAnalysisSource.Tokenize(" ");
1900 while((str=(TObjString*)next())) {
1901 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1903 if (list) delete list;
1906 out << "// connect to AliEn and make the chain" << endl;
1907 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1908 if (IsUsingTags()) {
1909 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1911 if(fFriendChainName!="AliAOD.VertexingHF.root") {
1912 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1914 out << " // Check if the macro to create the chain was provided" << endl;
1915 out << " if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1916 out << " ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1917 out << " return;" << endl;
1918 out << " }" << endl;
1919 out << " gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1920 out << " TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1923 out << "// read the analysis manager from file" << endl;
1924 TString analysisFile = fExecutable;
1925 analysisFile.ReplaceAll(".sh", ".root");
1926 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1927 out << " if (!file) return;" << endl;
1928 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1929 out << " AliAnalysisManager *mgr = 0;" << endl;
1930 out << " TKey *key;" << endl;
1931 out << " while ((key=(TKey*)nextkey())) {" << endl;
1932 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1933 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1934 out << " };" << endl;
1935 out << " if (!mgr) {" << endl;
1936 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1937 out << " return;" << endl;
1938 out << " }" << endl << endl;
1939 out << " mgr->PrintStatus();" << endl;
1940 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1941 out << " timer.Stop();" << endl;
1942 out << " timer.Print();" << endl;
1943 out << "}" << endl << endl;
1944 if (IsUsingTags()) {
1945 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1947 out << "// Create a chain using tags from the xml file." << endl;
1948 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1949 out << " if (!coll) {" << endl;
1950 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1951 out << " return NULL;" << endl;
1952 out << " }" << endl;
1953 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1954 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1955 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1956 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1957 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1958 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1959 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1960 out << " // Check if the cuts configuration file was provided" << endl;
1961 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1962 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1963 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1964 out << " }" << endl;
1965 if (fFriendChainName=="") {
1966 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1968 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1969 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1970 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1972 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1973 out << " chain->ls();" << endl;
1974 out << " return chain;" << endl;
1975 out << "}" << endl << endl;
1976 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1977 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1978 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1979 msg += " AliLHCTagCuts *lhcCuts,\n";
1980 msg += " AliDetectorTagCuts *detCuts,\n";
1981 msg += " AliEventTagCuts *evCuts)";
1982 Info("WriteAnalysisMacro", msg.Data());
1985 if (!IsUsingTags() || fFriendChainName!="") {
1986 out <<"//________________________________________________________________________________" << endl;
1987 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1989 out << "// Create a chain using url's from xml file" << endl;
1990 out << " TString treename = type;" << endl;
1991 out << " treename.ToLower();" << endl;
1992 out << " treename += \"Tree\";" << endl;
1993 out << " printf(\"***************************************\\n\");" << endl;
1994 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
1995 out << " printf(\"***************************************\\n\");" << endl;
1996 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1997 out << " if (!coll) {" << endl;
1998 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1999 out << " return NULL;" << endl;
2000 out << " }" << endl;
2001 out << " TChain *chain = new TChain(treename);" << endl;
2002 if(fFriendChainName!="") {
2003 out << " TChain *chainFriend = new TChain(treename);" << endl;
2005 out << " coll->Reset();" << endl;
2006 out << " while (coll->Next()) {" << endl;
2007 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
2008 if(fFriendChainName!="") {
2009 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
2010 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2011 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2012 out << " chainFriend->Add(fileFriend.Data());" << endl;
2014 out << " }" << endl;
2015 out << " if (!chain->GetNtrees()) {" << endl;
2016 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2017 out << " return NULL;" << endl;
2018 out << " }" << endl;
2019 if(fFriendChainName!="") {
2020 out << " chain->AddFriend(chainFriend);" << endl;
2022 out << " return chain;" << endl;
2023 out << "}" << endl << endl;
2026 out <<"//________________________________________________________________________________" << endl;
2027 out << "Bool_t SetupPar(const char *package) {" << endl;
2028 out << "// Compile the package and set it up." << endl;
2029 out << " TString pkgdir = package;" << endl;
2030 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2031 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2032 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2033 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2034 out << " // Check for BUILD.sh and execute" << endl;
2035 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2036 out << " printf(\"*******************************\\n\");" << endl;
2037 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2038 out << " printf(\"*******************************\\n\");" << endl;
2039 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2040 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2041 out << " gSystem->ChangeDirectory(cdir);" << endl;
2042 out << " return kFALSE;" << endl;
2043 out << " }" << endl;
2044 out << " } else {" << endl;
2045 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2046 out << " gSystem->ChangeDirectory(cdir);" << endl;
2047 out << " return kFALSE;" << endl;
2048 out << " }" << endl;
2049 out << " // Check for SETUP.C and execute" << endl;
2050 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2051 out << " printf(\"*******************************\\n\");" << endl;
2052 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2053 out << " printf(\"*******************************\\n\");" << endl;
2054 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2055 out << " } else {" << endl;
2056 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2057 out << " gSystem->ChangeDirectory(cdir);" << endl;
2058 out << " return kFALSE;" << endl;
2059 out << " }" << endl;
2060 out << " // Restore original workdir" << endl;
2061 out << " gSystem->ChangeDirectory(cdir);" << endl;
2062 out << " return kTRUE;" << endl;
2065 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2067 Bool_t copy = kTRUE;
2068 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2071 TString workdir = gGrid->GetHomeDirectory();
2072 workdir += fGridWorkingDir;
2073 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2074 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2075 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2076 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2077 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2079 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2080 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2084 //______________________________________________________________________________
2085 void AliAnalysisAlien::WriteExecutable()
2087 // Generate the alien executable script.
2088 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2090 out.open(fExecutable.Data(), ios::out);
2092 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2095 out << "#!/bin/bash" << endl;
2096 out << "echo \"=========================================\"" << endl;
2097 out << "echo \"############## PATH : ##############\"" << endl;
2098 out << "echo $PATH" << endl;
2099 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2100 out << "echo $LD_LIBRARY_PATH" << endl;
2101 out << "echo \"############## ROOTSYS : ##############\"" << endl;
2102 out << "echo $ROOTSYS" << endl;
2103 out << "echo \"############## which root : ##############\"" << endl;
2104 out << "which root" << endl;
2105 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2106 out << "echo $ALICE_ROOT" << endl;
2107 out << "echo \"############## which aliroot : ##############\"" << endl;
2108 out << "which aliroot" << endl;
2109 out << "echo \"############## system limits : ##############\"" << endl;
2110 out << "ulimit -a" << endl;
2111 out << "echo \"############## memory : ##############\"" << endl;
2112 out << "free -m" << endl;
2113 out << "echo \"=========================================\"" << endl << endl;
2114 // Make sure we can properly compile par files
2115 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2116 out << fExecutableCommand << " ";
2117 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2118 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2119 out << "echo \"############## memory after: ##############\"" << endl;
2120 out << "free -m" << endl;
2121 out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2122 out << "dmesg | tail -n 10" << endl;
2124 Bool_t copy = kTRUE;
2125 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2128 TString workdir = gGrid->GetHomeDirectory();
2129 TString bindir = Form("%s/bin", workdir.Data());
2130 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2131 workdir += fGridWorkingDir;
2132 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2133 if (FileExists(executable)) gGrid->Rm(executable);
2134 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2135 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2139 //______________________________________________________________________________
2140 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2142 // Write the production file to be submitted by LPM manager. The format is:
2143 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2144 // Next lines: full_path_to_dataset XXX (XXX is a string)
2145 // To submit, one has to: submit jdl XXX for all lines
2147 out.open(filename, ios::out);
2149 Error("WriteProductionFile", "Bad file name: %s", filename);
2152 TString workdir = gGrid->GetHomeDirectory();
2153 workdir += fGridWorkingDir;
2154 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2155 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2156 out << locjdl << " " << njobspermaster << endl;
2157 Int_t nmasterjobs = fInputFiles->GetEntries();
2158 for (Int_t i=0; i<nmasterjobs; i++) {
2159 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2161 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
2162 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
2165 //______________________________________________________________________________
2166 void AliAnalysisAlien::WriteValidationScript()
2168 // Generate the alien validation script.
2169 // Generate the validation script
2171 TString validationScript = fExecutable;
2172 validationScript.ReplaceAll(".sh", "_validation.sh");
2174 Error("WriteValidationScript", "Alien connection required");
2177 TString out_stream = "";
2178 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2179 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2181 out.open(validationScript, ios::out);
2182 out << "#!/bin/bash" << endl;
2183 out << "##################################################" << endl;
2184 out << "validateout=`dirname $0`" << endl;
2185 out << "validatetime=`date`" << endl;
2186 out << "validated=\"0\";" << endl;
2187 out << "error=0" << endl;
2188 out << "if [ -z $validateout ]" << endl;
2189 out << "then" << endl;
2190 out << " validateout=\".\"" << endl;
2191 out << "fi" << endl << endl;
2192 out << "cd $validateout;" << endl;
2193 out << "validateworkdir=`pwd`;" << endl << endl;
2194 out << "echo \"*******************************************************\"" << out_stream << endl;
2195 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
2197 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
2198 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
2199 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
2200 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2201 out << "ls -la ./" << out_stream << endl;
2202 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
2203 out << "##################################################" << endl;
2206 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2207 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2208 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2211 out << "if [ ! -f stderr ] ; then" << endl;
2212 out << " error=1" << endl;
2213 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
2214 out << " echo \"Error = $error\" " << out_stream << endl;
2215 out << "fi" << endl;
2217 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2218 out << " error=1" << endl;
2219 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
2220 out << " echo \"$parArch\" " << out_stream << endl;
2221 out << " echo \"Error = $error\" " << out_stream << endl;
2222 out << "fi" << endl;
2224 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2225 out << " error=1" << endl;
2226 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
2227 out << " echo \"$segViol\" " << out_stream << endl;
2228 out << " echo \"Error = $error\" " << out_stream << endl;
2229 out << "fi" << endl;
2231 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2232 out << " error=1" << endl;
2233 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
2234 out << " echo \"$segFault\" " << out_stream << endl;
2235 out << " echo \"Error = $error\" " << out_stream << endl;
2236 out << "fi" << endl;
2238 // Part dedicated to the specific analyses running into the train
2240 TObjArray *arr = fOutputFiles.Tokenize(" ");
2242 TString output_file;
2243 while ((os=(TObjString*)next1())) {
2244 output_file = os->GetString();
2245 Int_t index = output_file.Index("@");
2246 if (index > 0) output_file.Remove(index);
2247 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2248 out << " error=1" << endl;
2249 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
2250 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2251 out << "fi" << endl;
2254 out << "if ! [ -f outputs_valid ] ; then" << endl;
2255 out << " error=1" << endl;
2256 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2257 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2258 out << "fi" << endl;
2260 out << "if [ $error = 0 ] ; then" << endl;
2261 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
2262 out << "fi" << endl;
2264 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2265 out << "echo \"*******************************************************\"" << out_stream << endl;
2266 out << "cd -" << endl;
2267 out << "exit $error" << endl;
2269 Bool_t copy = kTRUE;
2270 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2273 TString workdir = gGrid->GetHomeDirectory();
2274 workdir += fGridWorkingDir;
2275 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
2276 if (FileExists(validationScript)) gGrid->Rm(validationScript);
2277 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));