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 if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
926 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
927 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
934 //______________________________________________________________________________
935 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
937 // Writes one or more JDL's corresponding to findex. If findex is negative,
938 // all run numbers are considered in one go (jdl). For non-negative indices
939 // they correspond to the indices in the array fInputFiles.
940 if (!fInputFiles) return kFALSE;
942 TString workdir = gGrid->GetHomeDirectory();
943 workdir += fGridWorkingDir;
945 if (!fRunNumbers.Length() && !fRunRange[0]) {
946 // One jdl with no parameters in case input data is specified by name.
947 TIter next(fInputFiles);
948 while ((os=(TObjString*)next()))
949 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
950 if (!fOutputSingle.IsNull())
951 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()));
953 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
955 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
956 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
957 if (!fOutputSingle.IsNull()) {
958 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
959 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()));
961 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
966 // Generate the JDL as a string
967 TString sjdl = fGridJDL->Generate();
969 index = sjdl.Index("Executable");
970 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
971 index = sjdl.Index("Split ");
972 if (index >= 0) sjdl.Insert(index, "\n# We split per SE or file\n");
973 index = sjdl.Index("SplitMaxInputFileNumber");
974 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
975 index = sjdl.Index("InputDataCollection");
976 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
977 index = sjdl.Index("InputFile");
978 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
979 index = sjdl.Index("InputDataList ");
980 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
981 index = sjdl.Index("InputDataListFormat");
982 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
983 index = sjdl.Index("Price");
984 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
985 index = sjdl.Index("Requirements");
986 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
987 index = sjdl.Index("Packages");
988 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
989 index = sjdl.Index("User =");
990 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
991 index = sjdl.Index("TTL");
992 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
993 index = sjdl.Index("OutputFile");
994 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
995 index = sjdl.Index("OutputDir");
996 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
997 index = sjdl.Index("OutputArchive");
998 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
999 index = sjdl.Index("MaxInitFailed");
1000 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
1001 index = sjdl.Index("MasterResubmitThreshold");
1002 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
1003 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
1004 index = sjdl.Index("Validationcommand");
1005 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
1006 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1007 sjdl.ReplaceAll("(member", "\n (member");
1008 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1009 sjdl.ReplaceAll("{", "{\n ");
1010 sjdl.ReplaceAll("};", "\n};");
1011 sjdl.ReplaceAll("{\n \n", "{\n");
1012 sjdl.ReplaceAll("\n\n", "\n");
1013 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1014 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1015 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
1016 index = sjdl.Index("JDLVariables");
1017 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1018 // Write jdl to file
1020 out.open(fJDLName.Data(), ios::out);
1022 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1025 out << sjdl << endl;
1027 // Copy jdl to grid workspace
1029 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1031 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1032 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1033 if (fProductionMode)
1034 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1035 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1036 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1041 //______________________________________________________________________________
1042 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1044 // Returns true if file exists.
1045 if (!gGrid) return kFALSE;
1046 TGridResult *res = gGrid->Ls(lfn);
1047 if (!res) return kFALSE;
1048 TMap *map = dynamic_cast<TMap*>(res->At(0));
1053 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1054 if (!objs || !objs->GetString().Length()) {
1062 //______________________________________________________________________________
1063 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1065 // Returns true if directory exists. Can be also a path.
1066 if (!gGrid) return kFALSE;
1067 // Check if dirname is a path
1068 TString dirstripped = dirname;
1069 dirstripped = dirstripped.Strip();
1070 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1071 TString dir = gSystem->BaseName(dirstripped);
1073 TString path = gSystem->DirName(dirstripped);
1074 TGridResult *res = gGrid->Ls(path, "-F");
1075 if (!res) return kFALSE;
1079 while ((map=dynamic_cast<TMap*>(next()))) {
1080 obj = map->GetValue("name");
1082 if (dir == obj->GetName()) {
1091 //______________________________________________________________________________
1092 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1094 // Check input data type.
1095 is_collection = kFALSE;
1099 Error("CheckDataType", "No connection to grid");
1102 is_collection = IsCollection(lfn);
1103 TString msg = "\n##### file: ";
1105 if (is_collection) {
1106 msg += " type: raw_collection;";
1107 // special treatment for collections
1109 // check for tag files in the collection
1110 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1112 msg += " using_tags: No (unknown)";
1113 Info("CheckDataType", msg.Data());
1116 const char* typeStr = res->GetKey(0, "origLFN");
1117 if (!typeStr || !strlen(typeStr)) {
1118 msg += " using_tags: No (unknown)";
1119 Info("CheckDataType", msg.Data());
1122 TString file = typeStr;
1123 use_tags = file.Contains(".tag");
1124 if (use_tags) msg += " using_tags: Yes";
1125 else msg += " using_tags: No";
1126 Info("CheckDataType", msg.Data());
1131 is_xml = slfn.Contains(".xml");
1133 // Open xml collection and check if there are tag files inside
1134 msg += " type: xml_collection;";
1135 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1137 msg += " using_tags: No (unknown)";
1138 Info("CheckDataType", msg.Data());
1141 TMap *map = coll->Next();
1143 msg += " using_tags: No (unknown)";
1144 Info("CheckDataType", msg.Data());
1147 map = (TMap*)map->GetValue("");
1149 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1150 use_tags = file.Contains(".tag");
1152 if (use_tags) msg += " using_tags: Yes";
1153 else msg += " using_tags: No";
1154 Info("CheckDataType", msg.Data());
1157 use_tags = slfn.Contains(".tag");
1158 if (slfn.Contains(".root")) msg += " type: root file;";
1159 else msg += " type: unhnown file;";
1160 if (use_tags) msg += " using_tags: Yes";
1161 else msg += " using_tags: No";
1162 Info("CheckDataType", msg.Data());
1165 //______________________________________________________________________________
1166 void AliAnalysisAlien::EnablePackage(const char *package)
1168 // Enables a par file supposed to exist in the current directory.
1169 TString pkg(package);
1170 pkg.ReplaceAll(".par", "");
1172 if (gSystem->AccessPathName(pkg)) {
1173 Error("EnablePackage", "Package %s not found", pkg.Data());
1176 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1177 Info("EnablePackage", "AliEn plugin will use .par packages");
1178 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1180 fPackages = new TObjArray();
1181 fPackages->SetOwner();
1183 fPackages->Add(new TObjString(pkg));
1186 //______________________________________________________________________________
1187 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1189 // Get job status for all jobs with jobid>jobidstart.
1190 static char mstatus[20];
1196 TGridJobStatusList *list = gGrid->Ps("");
1197 if (!list) return mstatus;
1198 Int_t nentries = list->GetSize();
1199 TGridJobStatus *status;
1201 for (Int_t ijob=0; ijob<nentries; ijob++) {
1202 status = (TGridJobStatus *)list->At(ijob);
1203 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1204 if (pid<jobidstart) continue;
1205 if (pid == lastid) {
1206 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1208 switch (status->GetStatus()) {
1209 case TGridJobStatus::kWAITING:
1211 case TGridJobStatus::kRUNNING:
1213 case TGridJobStatus::kABORTED:
1214 case TGridJobStatus::kFAIL:
1215 case TGridJobStatus::kUNKNOWN:
1217 case TGridJobStatus::kDONE:
1226 //______________________________________________________________________________
1227 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1229 // Returns true if file is a collection. Functionality duplicated from
1230 // TAlien::Type() because we don't want to directly depend on TAlien.
1232 Error("IsCollection", "No connection to grid");
1235 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1236 if (!res) return kFALSE;
1237 const char* typeStr = res->GetKey(0, "type");
1238 if (!typeStr || !strlen(typeStr)) return kFALSE;
1239 if (!strcmp(typeStr, "collection")) return kTRUE;
1244 //______________________________________________________________________________
1245 Bool_t AliAnalysisAlien::IsSingleOutput() const
1247 // Check if single-ouput option is on.
1248 return (!fOutputSingle.IsNull());
1251 //______________________________________________________________________________
1252 void AliAnalysisAlien::Print(Option_t *) const
1254 // Print current plugin settings.
1255 printf("### AliEn analysis plugin current settings ###\n");
1256 printf("= Production mode:______________________________ %d\n", fProductionMode);
1257 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1258 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1259 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1261 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1262 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1263 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1264 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1265 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1266 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1267 if (fRunNumbers.Length())
1268 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1270 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1271 if (!fRunRange[0] && !fRunNumbers.Length()) {
1272 TIter next(fInputFiles);
1275 while ((obj=next())) list += obj->GetName();
1276 printf("= Input files to be processed: _________________ %s\n", list.Data());
1278 if (TestBit(AliAnalysisGrid::kTest))
1279 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1280 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1281 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1282 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1283 printf("=====================================================================\n");
1284 printf("= Job price: ___________________________________ %d\n", fPrice);
1285 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1286 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1287 if (fMaxInitFailed>0)
1288 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1289 if (fMasterResubmitThreshold>0)
1290 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1291 if (fNrunsPerMaster>0)
1292 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1293 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1294 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1295 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
1296 if (fArguments.Length())
1297 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1298 if (fExecutableArgs.Length())
1299 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1300 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1301 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1302 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1303 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1305 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1306 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1307 if (fIncludePath.Data())
1308 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1309 if (fCloseSE.Length())
1310 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1311 if (fFriendChainName.Length())
1312 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1314 TIter next(fPackages);
1317 while ((obj=next())) list += obj->GetName();
1318 printf("= Par files to be used: ________________________ %s\n", list.Data());
1322 //______________________________________________________________________________
1323 void AliAnalysisAlien::SetDefaults()
1325 // Set default values for everything. What cannot be filled will be left empty.
1326 if (fGridJDL) delete fGridJDL;
1327 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1330 fSplitMaxInputFileNumber = 100;
1332 fMasterResubmitThreshold = 0;
1336 fNrunsPerMaster = 1;
1337 fMaxMergeFiles = 100;
1339 fExecutable = "analysis.sh";
1340 fExecutableCommand = "root -b -q";
1342 fExecutableArgs = "";
1343 fAnalysisMacro = "myAnalysis.C";
1344 fAnalysisSource = "";
1345 fAdditionalLibs = "";
1349 fAliROOTVersion = "";
1350 fUser = ""; // Your alien user name
1351 fGridWorkingDir = "";
1352 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1353 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1354 fFriendChainName = "";
1355 fGridOutputDir = "output";
1356 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1357 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1358 fInputFormat = "xml-single";
1359 fJDLName = "analysis.jdl";
1360 fJobTag = "Automatically generated analysis JDL";
1361 fMergeExcludes = "";
1364 //______________________________________________________________________________
1365 Bool_t AliAnalysisAlien::MergeOutputs()
1367 // Merge analysis outputs existing in the AliEn space.
1368 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1369 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1371 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1374 // Get the output path
1375 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1376 if (!DirectoryExists(fGridOutputDir)) {
1377 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1380 if (!fOutputFiles.Length()) {
1381 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1384 TObjArray *list = fOutputFiles.Tokenize(" ");
1388 TString output_file;
1389 TString output_chunk;
1390 TString previous_chunk;
1391 Int_t count_chunk = 0;
1392 Int_t count_zero = fMaxMergeFiles;
1393 Bool_t merged = kTRUE;
1394 while((str=(TObjString*)next())) {
1395 output_file = str->GetString();
1396 Int_t index = output_file.Index("@");
1397 if (index > 0) output_file.Remove(index);
1398 // Skip already merged outputs
1399 if (!gSystem->AccessPathName(output_file)) {
1400 Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1403 if (fMergeExcludes.Length() &&
1404 fMergeExcludes.Contains(output_file.Data())) continue;
1405 // Perform a 'find' command in the output directory, looking for registered outputs
1406 command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1407 printf("command: %s\n", command.Data());
1408 TGridResult *res = gGrid->Command(command);
1410 TFileMerger *fm = 0;
1413 previous_chunk = "";
1415 // Check if there is a merge operation to resume
1416 output_chunk = output_file;
1417 output_chunk.ReplaceAll(".root", "_*.root");
1418 if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1420 for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1422 Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1426 output_chunk = output_file;
1427 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1428 printf("%s\n", output_chunk.Data());
1430 if (gSystem->AccessPathName(output_chunk)) continue;
1431 // Merged file with chunks up to <count_chunk> found
1432 printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1433 previous_chunk = output_chunk;
1437 count_zero = fMaxMergeFiles;
1438 while ((map=(TMap*)nextmap())) {
1439 // Loop 'find' results and get next LFN
1440 if (count_zero == fMaxMergeFiles) {
1441 // First file in chunk - create file merger and add previous chunk if any.
1442 fm = new TFileMerger(kFALSE);
1443 fm->SetFastMethod(kTRUE);
1444 if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1445 output_chunk = output_file;
1446 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1448 // If last file found, put merged results in the output file
1449 if (map == res->Last()) output_chunk = output_file;
1450 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1451 if (!objs || !objs->GetString().Length()) {
1452 // Nothing found - skip this output
1457 // Add file to be merged and decrement chunk counter.
1458 fm->AddFile(objs->GetString());
1460 if (count_zero==0 || map == res->Last()) {
1461 fm->OutputFile(output_chunk);
1462 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1463 // Nothing found - skip this output
1464 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1469 // Merge the outputs, then go to next chunk
1471 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1477 Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1478 gSystem->Unlink(previous_chunk);
1480 if (map == res->Last()) {
1486 count_zero = fMaxMergeFiles;
1487 previous_chunk = output_chunk;
1492 Error("MergeOutputs", "Terminate() will NOT be executed");
1497 //______________________________________________________________________________
1498 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1500 // Use the output files connected to output containers from the analysis manager
1501 // rather than the files defined by SetOutputFiles
1502 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1503 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1505 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1508 //______________________________________________________________________________
1509 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1511 // Start remote grid analysis.
1513 // Check if output files have to be taken from the analysis manager
1514 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1515 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1516 if (!mgr || !mgr->IsInitialized()) {
1517 Error("StartAnalysis", "You need an initialized analysis manager for this");
1521 TIter next(mgr->GetOutputs());
1522 AliAnalysisDataContainer *output;
1523 while ((output=(AliAnalysisDataContainer*)next())) {
1524 const char *filename = output->GetFileName();
1525 if (!(strcmp(filename, "default"))) {
1526 if (!mgr->GetOutputEventHandler()) continue;
1527 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1529 if (fOutputFiles.Contains(filename)) continue;
1530 if (fOutputFiles.Length()) fOutputFiles += " ";
1531 fOutputFiles += filename;
1533 // Add extra files registered to the analysis manager
1534 if (mgr->GetExtraFiles().Length()) {
1535 if (fOutputFiles.Length()) fOutputFiles += " ";
1536 fOutputFiles += mgr->GetExtraFiles();
1539 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1540 if (TestBit(AliAnalysisGrid::kOffline)) {
1541 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1542 \n there nor any job run. You can revise the JDL and analysis \
1543 \n macro then run the same in \"submit\" mode.");
1544 } else if (TestBit(AliAnalysisGrid::kTest)) {
1545 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1547 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1548 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1549 \n space and job submitted.");
1550 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1551 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1554 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1558 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1562 if (!CheckInputData()) {
1563 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1566 CreateDataset(fDataPattern);
1567 WriteAnalysisFile();
1568 WriteAnalysisMacro();
1570 WriteValidationScript();
1571 if (!CreateJDL()) return kFALSE;
1572 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1573 if (TestBit(AliAnalysisGrid::kTest)) {
1574 // Locally testing the analysis
1575 Info("StartAnalysis", "\n_______________________________________________________________________ \
1576 \n Running analysis script in a daughter shell as on a worker node \
1577 \n_______________________________________________________________________");
1578 TObjArray *list = fOutputFiles.Tokenize(" ");
1581 TString output_file;
1582 while((str=(TObjString*)next())) {
1583 output_file = str->GetString();
1584 Int_t index = output_file.Index("@");
1585 if (index > 0) output_file.Remove(index);
1586 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1589 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1590 TString validationScript = fExecutable;
1591 validationScript.ReplaceAll(".sh", "_validation.sh");
1592 gSystem->Exec(Form("bash %s",validationScript.Data()));
1593 // gSystem->Exec("cat stdout");
1596 // Check if submitting is managed by LPM manager
1597 if (fProductionMode) {
1598 TString prodfile = fJDLName;
1599 prodfile.ReplaceAll(".jdl", ".prod");
1600 WriteProductionFile(prodfile);
1601 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1604 // Submit AliEn job(s)
1605 gGrid->Cd(fGridOutputDir);
1608 if (!fRunNumbers.Length() && !fRunRange[0]) {
1609 // Submit a given xml or a set of runs
1610 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1611 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1613 const char *cjobId = res->GetKey(0,"jobId");
1615 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1618 Info("StartAnalysis", "\n_______________________________________________________________________ \
1619 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1620 \n_______________________________________________________________________",
1621 fJDLName.Data(), cjobId);
1627 // Submit for a range of enumeration of runs.
1631 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1632 \n You may exit at any time and terminate the job later using the option <terminate> \
1633 \n ##################################################################################", jobID.Data());
1634 gSystem->Exec("aliensh");
1638 //______________________________________________________________________________
1639 void AliAnalysisAlien::Submit()
1641 // Submit all master jobs.
1642 Int_t nmasterjobs = fInputFiles->GetEntries();
1643 Long_t tshoot = gSystem->Now();
1644 if (!fNsubmitted) SubmitNext();
1645 while (fNsubmitted < nmasterjobs) {
1646 Long_t now = gSystem->Now();
1647 if ((now-tshoot)>30000) {
1654 //______________________________________________________________________________
1655 void AliAnalysisAlien::SubmitNext()
1657 // Submit next bunch of master jobs if the queue is free.
1658 static Bool_t iscalled = kFALSE;
1659 static Int_t firstmaster = 0;
1660 static Int_t lastmaster = 0;
1661 static Int_t npermaster = 0;
1662 if (iscalled) return;
1664 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1665 Int_t ntosubmit = 0;
1668 if (!fNsubmitted) ntosubmit = 1;
1670 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1671 printf("=== master %d: %s\n", lastmaster, status.Data());
1672 // If last master not split, just return
1673 if (status != "SPLIT") {iscalled = kFALSE; return;}
1674 // No more than 100 waiting jobs
1675 if (nwaiting>100) {iscalled = kFALSE; return;}
1676 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
1677 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1678 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
1679 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1681 Int_t nmasterjobs = fInputFiles->GetEntries();
1682 for (Int_t i=0; i<ntosubmit; i++) {
1683 // Submit for a range of enumeration of runs.
1684 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1686 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
1687 runOutDir.ReplaceAll(".xml", "");
1689 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
1691 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1692 printf("********* %s\n",query.Data());
1693 res = gGrid->Command(query);
1695 TString cjobId1 = res->GetKey(0,"jobId");
1696 if (!cjobId1.Length()) {
1697 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1701 Info("StartAnalysis", "\n_______________________________________________________________________ \
1702 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1703 \n_______________________________________________________________________",
1704 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1707 lastmaster = cjobId1.Atoi();
1708 if (!firstmaster) firstmaster = lastmaster;
1717 //______________________________________________________________________________
1718 void AliAnalysisAlien::WriteAnalysisFile()
1720 // Write current analysis manager into the file <analysisFile>
1721 TString analysisFile = fExecutable;
1722 analysisFile.ReplaceAll(".sh", ".root");
1723 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1724 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1725 if (!mgr || !mgr->IsInitialized()) {
1726 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1729 // Check analysis type
1731 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1732 handler = (TObject*)mgr->GetInputEventHandler();
1734 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1735 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1737 TDirectory *cdir = gDirectory;
1738 TFile *file = TFile::Open(analysisFile, "RECREATE");
1740 // Skip task Terminate calls for the grid job
1741 mgr->SetSkipTerminate(kTRUE);
1742 // Unless merging makes no sense
1743 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
1746 // Enable termination for local jobs
1747 mgr->SetSkipTerminate(kFALSE);
1749 if (cdir) cdir->cd();
1750 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1752 Bool_t copy = kTRUE;
1753 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1756 TString workdir = gGrid->GetHomeDirectory();
1757 workdir += fGridWorkingDir;
1758 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1759 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1760 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1764 //______________________________________________________________________________
1765 void AliAnalysisAlien::WriteAnalysisMacro()
1767 // Write the analysis macro that will steer the analysis in grid mode.
1768 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1770 out.open(fAnalysisMacro.Data(), ios::out);
1772 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1775 TString func = fAnalysisMacro;
1776 TString type = "ESD";
1777 TString comment = "// Analysis using ";
1778 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1779 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1783 if (type!="AOD" && fFriendChainName!="") {
1784 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1787 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1788 else comment += " data";
1789 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1790 func.ReplaceAll(".C", "");
1791 out << "void " << func.Data() << "()" << endl;
1793 out << comment.Data() << endl;
1794 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1795 out << " TStopwatch timer;" << endl;
1796 out << " timer.Start();" << endl << endl;
1797 out << "// load base root libraries" << endl;
1798 out << " gSystem->Load(\"libTree\");" << endl;
1799 out << " gSystem->Load(\"libGeom\");" << endl;
1800 out << " gSystem->Load(\"libVMC\");" << endl;
1801 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
1802 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
1803 if (fAdditionalRootLibs.Length()) {
1804 // in principle libtree /lib geom libvmc etc. can go into this list, too
1805 out << "// Add aditional libraries" << endl;
1806 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
1809 while((str=(TObjString*)next())) {
1810 if (str->GetString().Contains(".so"))
1811 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1813 if (list) delete list;
1815 out << "// Load analysis framework libraries" << endl;
1819 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1820 out << " gSystem->Load(\"libESD\");" << endl;
1821 out << " gSystem->Load(\"libAOD\");" << endl;
1822 out << " gSystem->Load(\"libANALYSIS\");" << endl;
1823 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1824 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1826 TIter next(fPackages);
1829 Bool_t hasSTEERBase = kFALSE;
1830 Bool_t hasESD = kFALSE;
1831 Bool_t hasAOD = kFALSE;
1832 Bool_t hasANALYSIS = kFALSE;
1833 Bool_t hasANALYSISalice = kFALSE;
1834 Bool_t hasCORRFW = kFALSE;
1835 while ((obj=next())) {
1836 pkgname = obj->GetName();
1837 if (pkgname == "STEERBase" ||
1838 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1839 if (pkgname == "ESD" ||
1840 pkgname == "ESD.par") hasESD = kTRUE;
1841 if (pkgname == "AOD" ||
1842 pkgname == "AOD.par") hasAOD = kTRUE;
1843 if (pkgname == "ANALYSIS" ||
1844 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1845 if (pkgname == "ANALYSISalice" ||
1846 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1847 if (pkgname == "CORRFW" ||
1848 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
1850 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1851 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1852 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1853 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1854 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1855 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1856 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1857 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1858 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1859 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1860 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1861 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1862 out << "// Compile other par packages" << endl;
1864 while ((obj=next())) {
1865 pkgname = obj->GetName();
1866 if (pkgname == "STEERBase" ||
1867 pkgname == "STEERBase.par" ||
1869 pkgname == "ESD.par" ||
1871 pkgname == "AOD.par" ||
1872 pkgname == "ANALYSIS" ||
1873 pkgname == "ANALYSIS.par" ||
1874 pkgname == "ANALYSISalice" ||
1875 pkgname == "ANALYSISalice.par" ||
1876 pkgname == "CORRFW" ||
1877 pkgname == "CORRFW.par") continue;
1878 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1881 out << "// include path" << endl;
1882 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1883 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1884 if (fAdditionalLibs.Length()) {
1885 out << "// Add aditional AliRoot libraries" << endl;
1886 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1889 while((str=(TObjString*)next())) {
1890 if (str->GetString().Contains(".so"))
1891 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1893 if (list) delete list;
1896 out << "// analysis source to be compiled at runtime (if any)" << endl;
1897 if (fAnalysisSource.Length()) {
1898 TObjArray *list = fAnalysisSource.Tokenize(" ");
1901 while((str=(TObjString*)next())) {
1902 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1904 if (list) delete list;
1907 out << "// connect to AliEn and make the chain" << endl;
1908 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1909 if (IsUsingTags()) {
1910 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1912 if(fFriendChainName!="AliAOD.VertexingHF.root") {
1913 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1915 out << " // Check if the macro to create the chain was provided" << endl;
1916 out << " if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1917 out << " ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1918 out << " return;" << endl;
1919 out << " }" << endl;
1920 out << " gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1921 out << " TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1924 out << "// read the analysis manager from file" << endl;
1925 TString analysisFile = fExecutable;
1926 analysisFile.ReplaceAll(".sh", ".root");
1927 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1928 out << " if (!file) return;" << endl;
1929 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1930 out << " AliAnalysisManager *mgr = 0;" << endl;
1931 out << " TKey *key;" << endl;
1932 out << " while ((key=(TKey*)nextkey())) {" << endl;
1933 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1934 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1935 out << " };" << endl;
1936 out << " if (!mgr) {" << endl;
1937 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1938 out << " return;" << endl;
1939 out << " }" << endl << endl;
1940 out << " mgr->PrintStatus();" << endl;
1941 if (AliAnalysisManager::GetAnalysisManager()) {
1942 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>2) {
1943 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
1946 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1947 out << " timer.Stop();" << endl;
1948 out << " timer.Print();" << endl;
1949 out << "}" << endl << endl;
1950 if (IsUsingTags()) {
1951 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1953 out << "// Create a chain using tags from the xml file." << endl;
1954 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1955 out << " if (!coll) {" << endl;
1956 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1957 out << " return NULL;" << endl;
1958 out << " }" << endl;
1959 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1960 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1961 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1962 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1963 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1964 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1965 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1966 out << " // Check if the cuts configuration file was provided" << endl;
1967 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1968 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1969 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1970 out << " }" << endl;
1971 if (fFriendChainName=="") {
1972 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1974 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1975 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1976 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1978 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1979 out << " chain->ls();" << endl;
1980 out << " return chain;" << endl;
1981 out << "}" << endl << endl;
1982 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1983 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1984 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1985 msg += " AliLHCTagCuts *lhcCuts,\n";
1986 msg += " AliDetectorTagCuts *detCuts,\n";
1987 msg += " AliEventTagCuts *evCuts)";
1988 Info("WriteAnalysisMacro", msg.Data());
1991 if (!IsUsingTags() || fFriendChainName!="") {
1992 out <<"//________________________________________________________________________________" << endl;
1993 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1995 out << "// Create a chain using url's from xml file" << endl;
1996 out << " TString treename = type;" << endl;
1997 out << " treename.ToLower();" << endl;
1998 out << " treename += \"Tree\";" << endl;
1999 out << " printf(\"***************************************\\n\");" << endl;
2000 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
2001 out << " printf(\"***************************************\\n\");" << endl;
2002 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2003 out << " if (!coll) {" << endl;
2004 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2005 out << " return NULL;" << endl;
2006 out << " }" << endl;
2007 out << " TChain *chain = new TChain(treename);" << endl;
2008 if(fFriendChainName!="") {
2009 out << " TChain *chainFriend = new TChain(treename);" << endl;
2011 out << " coll->Reset();" << endl;
2012 out << " while (coll->Next()) {" << endl;
2013 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
2014 if(fFriendChainName!="") {
2015 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
2016 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2017 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2018 out << " chainFriend->Add(fileFriend.Data());" << endl;
2020 out << " }" << endl;
2021 out << " if (!chain->GetNtrees()) {" << endl;
2022 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2023 out << " return NULL;" << endl;
2024 out << " }" << endl;
2025 if(fFriendChainName!="") {
2026 out << " chain->AddFriend(chainFriend);" << endl;
2028 out << " return chain;" << endl;
2029 out << "}" << endl << endl;
2032 out <<"//________________________________________________________________________________" << endl;
2033 out << "Bool_t SetupPar(const char *package) {" << endl;
2034 out << "// Compile the package and set it up." << endl;
2035 out << " TString pkgdir = package;" << endl;
2036 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2037 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2038 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2039 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2040 out << " // Check for BUILD.sh and execute" << endl;
2041 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2042 out << " printf(\"*******************************\\n\");" << endl;
2043 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2044 out << " printf(\"*******************************\\n\");" << endl;
2045 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2046 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2047 out << " gSystem->ChangeDirectory(cdir);" << endl;
2048 out << " return kFALSE;" << endl;
2049 out << " }" << endl;
2050 out << " } else {" << endl;
2051 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2052 out << " gSystem->ChangeDirectory(cdir);" << endl;
2053 out << " return kFALSE;" << endl;
2054 out << " }" << endl;
2055 out << " // Check for SETUP.C and execute" << endl;
2056 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2057 out << " printf(\"*******************************\\n\");" << endl;
2058 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2059 out << " printf(\"*******************************\\n\");" << endl;
2060 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2061 out << " } else {" << endl;
2062 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2063 out << " gSystem->ChangeDirectory(cdir);" << endl;
2064 out << " return kFALSE;" << endl;
2065 out << " }" << endl;
2066 out << " // Restore original workdir" << endl;
2067 out << " gSystem->ChangeDirectory(cdir);" << endl;
2068 out << " return kTRUE;" << endl;
2071 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2073 Bool_t copy = kTRUE;
2074 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2077 TString workdir = gGrid->GetHomeDirectory();
2078 workdir += fGridWorkingDir;
2079 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2080 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2081 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2082 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2083 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2085 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2086 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2090 //______________________________________________________________________________
2091 void AliAnalysisAlien::WriteExecutable()
2093 // Generate the alien executable script.
2094 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2096 out.open(fExecutable.Data(), ios::out);
2098 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2101 out << "#!/bin/bash" << endl;
2102 out << "echo \"=========================================\"" << endl;
2103 out << "echo \"############## PATH : ##############\"" << endl;
2104 out << "echo $PATH" << endl;
2105 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2106 out << "echo $LD_LIBRARY_PATH" << endl;
2107 out << "echo \"############## ROOTSYS : ##############\"" << endl;
2108 out << "echo $ROOTSYS" << endl;
2109 out << "echo \"############## which root : ##############\"" << endl;
2110 out << "which root" << endl;
2111 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2112 out << "echo $ALICE_ROOT" << endl;
2113 out << "echo \"############## which aliroot : ##############\"" << endl;
2114 out << "which aliroot" << endl;
2115 out << "echo \"############## system limits : ##############\"" << endl;
2116 out << "ulimit -a" << endl;
2117 out << "echo \"############## memory : ##############\"" << endl;
2118 out << "free -m" << endl;
2119 out << "echo \"=========================================\"" << endl << endl;
2120 // Make sure we can properly compile par files
2121 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2122 out << fExecutableCommand << " ";
2123 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2124 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2125 out << "echo \"############## memory after: ##############\"" << endl;
2126 out << "free -m" << endl;
2127 out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2128 out << "dmesg | tail -n 10" << endl;
2130 Bool_t copy = kTRUE;
2131 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2134 TString workdir = gGrid->GetHomeDirectory();
2135 TString bindir = Form("%s/bin", workdir.Data());
2136 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2137 workdir += fGridWorkingDir;
2138 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2139 if (FileExists(executable)) gGrid->Rm(executable);
2140 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2141 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2145 //______________________________________________________________________________
2146 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2148 // Write the production file to be submitted by LPM manager. The format is:
2149 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2150 // Next lines: full_path_to_dataset XXX (XXX is a string)
2151 // To submit, one has to: submit jdl XXX for all lines
2153 out.open(filename, ios::out);
2155 Error("WriteProductionFile", "Bad file name: %s", filename);
2158 TString workdir = gGrid->GetHomeDirectory();
2159 workdir += fGridWorkingDir;
2160 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2161 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2162 out << locjdl << " " << njobspermaster << endl;
2163 Int_t nmasterjobs = fInputFiles->GetEntries();
2164 for (Int_t i=0; i<nmasterjobs; i++) {
2165 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2167 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
2168 if (FileExists(filename)) gGrid->Rm(filename);
2169 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
2172 //______________________________________________________________________________
2173 void AliAnalysisAlien::WriteValidationScript()
2175 // Generate the alien validation script.
2176 // Generate the validation script
2178 TString validationScript = fExecutable;
2179 validationScript.ReplaceAll(".sh", "_validation.sh");
2181 Error("WriteValidationScript", "Alien connection required");
2184 TString out_stream = "";
2185 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2186 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2188 out.open(validationScript, ios::out);
2189 out << "#!/bin/bash" << endl;
2190 out << "##################################################" << endl;
2191 out << "validateout=`dirname $0`" << endl;
2192 out << "validatetime=`date`" << endl;
2193 out << "validated=\"0\";" << endl;
2194 out << "error=0" << endl;
2195 out << "if [ -z $validateout ]" << endl;
2196 out << "then" << endl;
2197 out << " validateout=\".\"" << endl;
2198 out << "fi" << endl << endl;
2199 out << "cd $validateout;" << endl;
2200 out << "validateworkdir=`pwd`;" << endl << endl;
2201 out << "echo \"*******************************************************\"" << out_stream << endl;
2202 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
2204 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
2205 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
2206 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
2207 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2208 out << "ls -la ./" << out_stream << endl;
2209 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
2210 out << "##################################################" << endl;
2213 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2214 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2215 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2218 out << "if [ ! -f stderr ] ; then" << endl;
2219 out << " error=1" << endl;
2220 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
2221 out << " echo \"Error = $error\" " << out_stream << endl;
2222 out << "fi" << endl;
2224 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2225 out << " error=1" << endl;
2226 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
2227 out << " echo \"$parArch\" " << out_stream << endl;
2228 out << " echo \"Error = $error\" " << out_stream << endl;
2229 out << "fi" << endl;
2231 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2232 out << " error=1" << endl;
2233 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
2234 out << " echo \"$segViol\" " << out_stream << endl;
2235 out << " echo \"Error = $error\" " << out_stream << endl;
2236 out << "fi" << endl;
2238 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2239 out << " error=1" << endl;
2240 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
2241 out << " echo \"$segFault\" " << out_stream << endl;
2242 out << " echo \"Error = $error\" " << out_stream << endl;
2243 out << "fi" << endl;
2245 // Part dedicated to the specific analyses running into the train
2247 TObjArray *arr = fOutputFiles.Tokenize(" ");
2249 TString output_file;
2250 while ((os=(TObjString*)next1())) {
2251 output_file = os->GetString();
2252 Int_t index = output_file.Index("@");
2253 if (index > 0) output_file.Remove(index);
2254 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2255 out << " error=1" << endl;
2256 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
2257 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2258 out << "fi" << endl;
2261 out << "if ! [ -f outputs_valid ] ; then" << endl;
2262 out << " error=1" << endl;
2263 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2264 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2265 out << "fi" << endl;
2267 out << "if [ $error = 0 ] ; then" << endl;
2268 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
2269 out << "fi" << endl;
2271 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2272 out << "echo \"*******************************************************\"" << out_stream << endl;
2273 out << "cd -" << endl;
2274 out << "exit $error" << endl;
2276 Bool_t copy = kTRUE;
2277 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2280 TString workdir = gGrid->GetHomeDirectory();
2281 workdir += fGridWorkingDir;
2282 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
2283 if (FileExists(validationScript)) gGrid->Rm(validationScript);
2284 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));