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),
89 //______________________________________________________________________________
90 AliAnalysisAlien::AliAnalysisAlien(const char *name)
91 :AliAnalysisGrid(name),
95 fSplitMaxInputFileNumber(0),
97 fMasterResubmitThreshold(0),
135 //______________________________________________________________________________
136 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
137 :AliAnalysisGrid(other),
139 fPrice(other.fPrice),
141 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
142 fMaxInitFailed(other.fMaxInitFailed),
143 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
144 fNtestFiles(other.fNtestFiles),
145 fNrunsPerMaster(other.fNrunsPerMaster),
146 fMaxMergeFiles(other.fMaxMergeFiles),
147 fNsubmitted(other.fNsubmitted),
148 fProductionMode(other.fProductionMode),
149 fRunNumbers(other.fRunNumbers),
150 fExecutable(other.fExecutable),
151 fArguments(other.fArguments),
152 fAnalysisMacro(other.fAnalysisMacro),
153 fAnalysisSource(other.fAnalysisSource),
154 fAdditionalLibs(other.fAdditionalLibs),
155 fSplitMode(other.fSplitMode),
156 fAPIVersion(other.fAPIVersion),
157 fROOTVersion(other.fROOTVersion),
158 fAliROOTVersion(other.fAliROOTVersion),
160 fGridWorkingDir(other.fGridWorkingDir),
161 fGridDataDir(other.fGridDataDir),
162 fDataPattern(other.fDataPattern),
163 fGridOutputDir(other.fGridOutputDir),
164 fOutputArchive(other.fOutputArchive),
165 fOutputFiles(other.fOutputFiles),
166 fInputFormat(other.fInputFormat),
167 fDatasetName(other.fDatasetName),
168 fJDLName(other.fJDLName),
169 fMergeExcludes(other.fMergeExcludes),
170 fIncludePath(other.fIncludePath),
171 fCloseSE(other.fCloseSE),
172 fFriendChainName(other.fFriendChainName),
173 fJobTag(other.fJobTag),
178 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
179 fRunRange[0] = other.fRunRange[0];
180 fRunRange[1] = other.fRunRange[1];
181 if (other.fInputFiles) {
182 fInputFiles = new TObjArray();
183 TIter next(other.fInputFiles);
185 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
186 fInputFiles->SetOwner();
188 if (other.fPackages) {
189 fPackages = new TObjArray();
190 TIter next(other.fPackages);
192 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
193 fPackages->SetOwner();
197 //______________________________________________________________________________
198 AliAnalysisAlien::~AliAnalysisAlien()
201 if (fGridJDL) delete fGridJDL;
202 if (fInputFiles) delete fInputFiles;
203 if (fPackages) delete fPackages;
206 //______________________________________________________________________________
207 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
210 if (this != &other) {
211 AliAnalysisGrid::operator=(other);
212 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
213 fPrice = other.fPrice;
215 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
216 fMaxInitFailed = other.fMaxInitFailed;
217 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
218 fNtestFiles = other.fNtestFiles;
219 fNrunsPerMaster = other.fNrunsPerMaster;
220 fMaxMergeFiles = other.fMaxMergeFiles;
221 fNsubmitted = other.fNsubmitted;
222 fProductionMode = other.fProductionMode;
223 fRunNumbers = other.fRunNumbers;
224 fExecutable = other.fExecutable;
225 fArguments = other.fArguments;
226 fAnalysisMacro = other.fAnalysisMacro;
227 fAnalysisSource = other.fAnalysisSource;
228 fAdditionalLibs = other.fAdditionalLibs;
229 fSplitMode = other.fSplitMode;
230 fAPIVersion = other.fAPIVersion;
231 fROOTVersion = other.fROOTVersion;
232 fAliROOTVersion = other.fAliROOTVersion;
234 fGridWorkingDir = other.fGridWorkingDir;
235 fGridDataDir = other.fGridDataDir;
236 fDataPattern = other.fDataPattern;
237 fGridOutputDir = other.fGridOutputDir;
238 fOutputArchive = other.fOutputArchive;
239 fOutputFiles = other.fOutputFiles;
240 fInputFormat = other.fInputFormat;
241 fDatasetName = other.fDatasetName;
242 fJDLName = other.fJDLName;
243 fMergeExcludes = other.fMergeExcludes;
244 fIncludePath = other.fIncludePath;
245 fCloseSE = other.fCloseSE;
246 fFriendChainName = other.fFriendChainName;
247 fJobTag = other.fJobTag;
248 if (other.fInputFiles) {
249 fInputFiles = new TObjArray();
250 TIter next(other.fInputFiles);
252 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
253 fInputFiles->SetOwner();
255 if (other.fPackages) {
256 fPackages = new TObjArray();
257 TIter next(other.fPackages);
259 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
260 fPackages->SetOwner();
266 //______________________________________________________________________________
267 void AliAnalysisAlien::AddIncludePath(const char *path)
269 // Add include path in the remote analysis macro.
271 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
272 else fIncludePath += Form("-I%s ", path);
275 //______________________________________________________________________________
276 void AliAnalysisAlien::AddRunNumber(Int_t run)
278 // Add a run number to the list of runs to be processed.
279 if (fRunNumbers.Length()) fRunNumbers += " ";
280 fRunNumbers += Form("%d", run);
283 //______________________________________________________________________________
284 void AliAnalysisAlien::AddRunNumber(const char* run)
286 // Add a run number to the list of runs to be processed.
287 if (fRunNumbers.Length()) fRunNumbers += " ";
291 //______________________________________________________________________________
292 void AliAnalysisAlien::AddDataFile(const char *lfn)
294 // Adds a data file to the input to be analysed. The file should be a valid LFN
295 // or point to an existing file in the alien workdir.
296 if (!fInputFiles) fInputFiles = new TObjArray();
297 fInputFiles->Add(new TObjString(lfn));
300 //______________________________________________________________________________
301 Bool_t AliAnalysisAlien::Connect()
303 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
304 if (gGrid && gGrid->IsConnected()) return kTRUE;
305 if (!gSystem->Getenv("alien_API_USER")) {
306 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
307 gSystem->Getenv("UID"));
311 Info("Connect", "Trying to connect to AliEn ...");
312 TGrid::Connect("alien://");
314 if (!gGrid || !gGrid->IsConnected()) {
315 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
318 fUser = gGrid->GetUser();
319 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
323 //______________________________________________________________________________
324 void AliAnalysisAlien::CdWork()
326 // Check validity of alien workspace. Create directory if possible.
328 Error("CdWork", "Alien connection required");
331 TString homedir = gGrid->GetHomeDirectory();
332 TString workdir = homedir + fGridWorkingDir;
333 if (DirectoryExists(workdir)) {
337 // Work directory not existing - create it
339 if (gGrid->Mkdir(workdir)) {
340 gGrid->Cd(fGridWorkingDir);
341 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
343 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
344 workdir.Data(), homedir.Data());
345 fGridWorkingDir = "";
349 //______________________________________________________________________________
350 Bool_t AliAnalysisAlien::CheckInputData()
352 // Check validity of input data. If necessary, create xml files.
353 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
354 if (!fGridDataDir.Length()) {
355 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
358 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
361 // Process declared files
362 Bool_t is_collection = kFALSE;
363 Bool_t is_xml = kFALSE;
364 Bool_t use_tags = kFALSE;
365 Bool_t checked = kFALSE;
368 TString workdir = gGrid->GetHomeDirectory();
369 workdir += fGridWorkingDir;
372 TIter next(fInputFiles);
373 while ((objstr=(TObjString*)next())) {
376 file += objstr->GetString();
377 // Store full lfn path
378 if (FileExists(file)) objstr->SetString(file);
380 file = objstr->GetName();
381 if (!FileExists(objstr->GetName())) {
382 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
383 objstr->GetName(), workdir.Data());
387 Bool_t iscoll, isxml, usetags;
388 CheckDataType(file, iscoll, isxml, usetags);
391 is_collection = iscoll;
394 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
396 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
397 Error("CheckInputData", "Some conflict was found in the types of inputs");
403 // Process requested run numbers
404 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
405 // Check validity of alien data directory
406 if (!fGridDataDir.Length()) {
407 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
410 if (!DirectoryExists(fGridDataDir)) {
411 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
415 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
419 if (checked && !is_xml) {
420 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
423 // Check validity of run number(s)
431 use_tags = fDataPattern.Contains("tag");
432 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
434 if (use_tags != fDataPattern.Contains("tag")) {
435 Error("CheckInputData", "Cannot mix input files using/not using tags");
438 if (fRunNumbers.Length()) {
439 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
440 arr = fRunNumbers.Tokenize(" ");
442 while ((os=(TObjString*)next())) {
443 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
444 if (!DirectoryExists(path)) {
445 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
448 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
449 TString msg = "\n##### file: ";
451 msg += " type: xml_collection;";
452 if (use_tags) msg += " using_tags: Yes";
453 else msg += " using_tags: No";
454 Info("CheckDataType", msg.Data());
455 if (fNrunsPerMaster<2) {
456 AddDataFile(Form("%s.xml", os->GetString().Data()));
459 if (((nruns-1)%fNrunsPerMaster) == 0) {
460 schunk = os->GetString();
462 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
463 schunk += Form("_%s.xml", os->GetString().Data());
469 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
470 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
471 path = Form("%s/%d ", fGridDataDir.Data(), irun);
472 if (!DirectoryExists(path)) {
473 // Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
476 path = Form("%s/%d.xml", workdir.Data(),irun);
477 TString msg = "\n##### file: ";
479 msg += " type: xml_collection;";
480 if (use_tags) msg += " using_tags: Yes";
481 else msg += " using_tags: No";
482 Info("CheckDataType", msg.Data());
483 if (fNrunsPerMaster<2) {
484 AddDataFile(Form("%d.xml",irun));
487 if (((nruns-1)%fNrunsPerMaster) == 0) {
488 schunk = Form("%d", irun);
490 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
491 schunk += Form("_%d.xml", irun);
499 //______________________________________________________________________________
500 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
502 // Create dataset for the grid data directory + run number.
503 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
505 Error("CreateDataset", "Cannot create dataset with no grid connection");
511 TString workdir = gGrid->GetHomeDirectory();
512 workdir += fGridWorkingDir;
514 // Compose the 'find' command arguments
516 TString options = "-x collection ";
517 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
518 TString conditions = "";
524 TGridCollection *cbase=0, *cadd=0;
525 if (!fRunNumbers.Length() && !fRunRange[0]) {
526 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
527 // Make a single data collection from data directory.
529 if (!DirectoryExists(path)) {
530 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
534 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
535 else file = Form("%s.xml", gSystem->BaseName(path));
536 if (gSystem->AccessPathName(file)) {
542 command += conditions;
543 Printf("command: %s", command.Data());
544 TGridResult *res = gGrid->Command(command);
546 // Write standard output to file
547 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
549 if (!TestBit(AliAnalysisGrid::kTest) && !FileExists(file)) {
550 // Copy xml file to alien space
551 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
552 if (!FileExists(file)) {
553 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
556 // Update list of files to be processed.
558 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
562 if (fRunNumbers.Length()) {
563 TObjArray *arr = fRunNumbers.Tokenize(" ");
566 while ((os=(TObjString*)next())) {
567 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
568 if (!DirectoryExists(path)) continue;
570 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
571 else file = Form("%s.xml", os->GetString().Data());
572 // If local collection file does not exist, create it via 'find' command.
573 if (gSystem->AccessPathName(file)) {
578 command += conditions;
579 TGridResult *res = gGrid->Command(command);
581 // Write standard output to file
582 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
584 if (TestBit(AliAnalysisGrid::kTest)) break;
585 // Check if there is one run per master job.
586 if (fNrunsPerMaster<2) {
587 if (FileExists(file)) {
588 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
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());
600 if (((nruns-1)%fNrunsPerMaster) == 0) {
601 schunk = os->GetString();
602 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
604 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
605 Printf(" Merging collection <%s> into masterjob input...", file.Data());
609 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
612 schunk += Form("_%s.xml", os->GetString().Data());
613 if (FileExists(schunk)) {
614 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
617 Printf("Exporting merged collection <%s> and copying to AliEn.", schunk.Data());
618 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
619 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
620 if (!FileExists(schunk)) {
621 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
629 // Process a full run range.
630 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
631 path = Form("%s/%d ", fGridDataDir.Data(), irun);
632 if (!DirectoryExists(path)) continue;
634 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
635 else file = Form("%d.xml", irun);
636 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
637 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
641 // If local collection file does not exist, create it via 'find' command.
642 if (gSystem->AccessPathName(file)) {
647 command += conditions;
648 TGridResult *res = gGrid->Command(command);
650 // Write standard output to file
651 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
653 if (TestBit(AliAnalysisGrid::kTest)) break;
654 // Check if there is one run per master job.
655 if (fNrunsPerMaster<2) {
656 if (FileExists(file)) {
657 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
660 // Copy xml file to alien space
661 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
662 if (!FileExists(file)) {
663 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
668 // Check if the collection for the chunk exist locally.
669 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
670 if (FileExists(fInputFiles->At(nchunk)->GetName())) continue;
671 Printf(" Merging collection <%s> into %d runs chunk...",file.Data(),fNrunsPerMaster);
672 if (((nruns-1)%fNrunsPerMaster) == 0) {
673 schunk = Form("%d", irun);
674 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
676 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
680 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1]) {
683 schunk += Form("_%d.xml", irun);
684 if (FileExists(schunk)) {
685 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
688 Printf("Exporting merged collection <%s> and copying to AliEn.", schunk.Data());
689 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
690 if (FileExists(schunk)) {
691 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
694 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
695 if (!FileExists(schunk)) {
696 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
705 //______________________________________________________________________________
706 Bool_t AliAnalysisAlien::CreateJDL()
708 // Generate a JDL file according to current settings. The name of the file is
709 // specified by fJDLName.
710 Bool_t error = kFALSE;
713 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
714 Bool_t generate = kTRUE;
715 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
717 Error("CreateJDL", "Alien connection required");
720 // Check validity of alien workspace
722 TString workdir = gGrid->GetHomeDirectory();
723 workdir += fGridWorkingDir;
727 Error("CreateJDL()", "Define some input files for your analysis.");
730 // Compose list of input files
731 // Check if output files were defined
732 if (!fOutputFiles.Length()) {
733 Error("CreateJDL", "You must define at least one output file");
736 // Check if an output directory was defined and valid
737 if (!fGridOutputDir.Length()) {
738 Error("CreateJDL", "You must define AliEn output directory");
741 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
742 if (!DirectoryExists(fGridOutputDir)) {
743 if (gGrid->Mkdir(fGridOutputDir)) {
744 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
746 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
752 // Exit if any error up to now
753 if (error) return kFALSE;
755 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
756 fGridJDL->SetExecutable(fExecutable);
757 // fGridJDL->SetTTL((UInt_t)fTTL);
758 fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
759 if (fMaxInitFailed > 0)
760 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
761 if (fSplitMaxInputFileNumber > 0)
762 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
763 if (fSplitMode.Length())
764 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
765 // fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
766 if (fAliROOTVersion.Length())
767 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
768 if (fROOTVersion.Length())
769 fGridJDL->AddToPackages("ROOT", fROOTVersion);
770 if (fAPIVersion.Length())
771 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
772 fGridJDL->SetInputDataListFormat(fInputFormat);
773 fGridJDL->SetInputDataList("wn.xml");
774 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
775 TString analysisFile = fExecutable;
776 analysisFile.ReplaceAll(".sh", ".root");
777 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
778 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
779 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
780 if (fAdditionalLibs.Length()) {
781 arr = fAdditionalLibs.Tokenize(" ");
783 while ((os=(TObjString*)next())) {
784 if (os->GetString().Contains(".so")) continue;
785 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
790 TIter next(fPackages);
793 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
795 if (fOutputArchive.Length()) {
796 arr = fOutputArchive.Tokenize(" ");
798 while ((os=(TObjString*)next()))
799 if (!os->GetString().Contains("@") && fCloseSE.Length())
800 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
802 fGridJDL->AddToOutputArchive(os->GetString());
805 arr = fOutputFiles.Tokenize(" ");
807 while ((os=(TObjString*)next())) {
808 // Ignore ouputs in jdl that are also in outputarchive
809 TString sout = os->GetString();
810 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
811 if (fOutputArchive.Contains(sout)) continue;
812 if (!os->GetString().Contains("@") && fCloseSE.Length())
813 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
815 fGridJDL->AddToOutputSandbox(os->GetString());
818 // fGridJDL->SetPrice((UInt_t)fPrice);
819 fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
820 TString validationScript = fExecutable;
821 validationScript.ReplaceAll(".sh", "_validation.sh");
822 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()));
823 if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
824 // Write a jdl with 2 input parameters: collection name and output dir name.
827 // Copy jdl to grid workspace
829 if (fAdditionalLibs.Length()) {
830 arr = fAdditionalLibs.Tokenize(" ");
833 while ((os=(TObjString*)next())) {
834 if (os->GetString().Contains(".so")) continue;
835 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
836 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
837 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
842 TIter next(fPackages);
844 while ((obj=next())) {
845 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
846 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
853 //______________________________________________________________________________
854 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
856 // Writes one or more JDL's corresponding to findex. If findex is negative,
857 // all run numbers are considered in one go (jdl). For non-negative indices
858 // they correspond to the indices in the array fInputFiles.
859 if (!fInputFiles) return kFALSE;
861 TString workdir = gGrid->GetHomeDirectory();
862 workdir += fGridWorkingDir;
864 if (!fRunNumbers.Length() && !fRunRange[0]) {
865 // One jdl with no parameters in case input data is specified by name.
866 TIter next(fInputFiles);
867 while ((os=(TObjString*)next()))
868 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
869 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
871 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
872 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
873 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
877 // Generate the JDL as a string
878 TString sjdl = fGridJDL->Generate();
880 index = sjdl.Index("Executable");
881 if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
882 index = sjdl.Index("Split ");
883 if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
884 index = sjdl.Index("SplitMaxInputFileNumber");
885 if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
886 index = sjdl.Index("InputDataCollection");
887 if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
888 index = sjdl.Index("InputFile");
889 if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
890 index = sjdl.Index("InputDataList ");
891 if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
892 index = sjdl.Index("InputDataListFormat");
893 if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
894 index = sjdl.Index("Price");
895 if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
896 index = sjdl.Index("Requirements");
897 if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
898 index = sjdl.Index("Packages");
899 if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
900 index = sjdl.Index("User =");
901 if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
902 index = sjdl.Index("TTL");
903 if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
904 index = sjdl.Index("OutputFile");
905 if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
906 index = sjdl.Index("OutputDir");
907 if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
908 index = sjdl.Index("OutputArchive");
909 if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
910 index = sjdl.Index("MaxInitFailed");
911 if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
912 index = sjdl.Index("MasterResubmitThreshold");
913 if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
914 sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
915 index = sjdl.Index("Validationcommand");
916 if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
917 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
918 sjdl.ReplaceAll("(member", "\n (member");
919 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
920 sjdl.ReplaceAll("{", "{\n ");
921 sjdl.ReplaceAll("};", "\n};");
922 sjdl.ReplaceAll("{\n \n", "{\n");
923 sjdl.ReplaceAll("\n\n", "\n");
924 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
925 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
926 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
927 index = sjdl.Index("JDLVariables");
928 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
931 out.open(fJDLName.Data(), ios::out);
933 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
938 // Copy jdl to grid workspace
940 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
942 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
943 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
945 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
946 if (FileExists(locjdl)) gGrid->Rm(locjdl);
947 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
952 //______________________________________________________________________________
953 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
955 // Returns true if file exists.
956 if (!gGrid) return kFALSE;
957 TGridResult *res = gGrid->Ls(lfn);
958 if (!res) return kFALSE;
959 TMap *map = dynamic_cast<TMap*>(res->At(0));
964 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
965 if (!objs || !objs->GetString().Length()) {
973 //______________________________________________________________________________
974 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
976 // Returns true if directory exists. Can be also a path.
977 if (!gGrid) return kFALSE;
978 // Check if dirname is a path
979 TString dirstripped = dirname;
980 dirstripped = dirstripped.Strip();
981 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
982 TString dir = gSystem->BaseName(dirstripped);
984 TString path = gSystem->DirName(dirstripped);
985 TGridResult *res = gGrid->Ls(path, "-F");
986 if (!res) return kFALSE;
990 while ((map=dynamic_cast<TMap*>(next()))) {
991 obj = map->GetValue("name");
993 if (dir == obj->GetName()) {
1002 //______________________________________________________________________________
1003 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1005 // Check input data type.
1006 is_collection = kFALSE;
1010 Error("CheckDataType", "No connection to grid");
1013 is_collection = IsCollection(lfn);
1014 TString msg = "\n##### file: ";
1016 if (is_collection) {
1017 msg += " type: raw_collection;";
1018 // special treatment for collections
1020 // check for tag files in the collection
1021 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1023 msg += " using_tags: No (unknown)";
1024 Info("CheckDataType", msg.Data());
1027 const char* typeStr = res->GetKey(0, "origLFN");
1028 if (!typeStr || !strlen(typeStr)) {
1029 msg += " using_tags: No (unknown)";
1030 Info("CheckDataType", msg.Data());
1033 TString file = typeStr;
1034 use_tags = file.Contains(".tag");
1035 if (use_tags) msg += " using_tags: Yes";
1036 else msg += " using_tags: No";
1037 Info("CheckDataType", msg.Data());
1042 is_xml = slfn.Contains(".xml");
1044 // Open xml collection and check if there are tag files inside
1045 msg += " type: xml_collection;";
1046 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1048 msg += " using_tags: No (unknown)";
1049 Info("CheckDataType", msg.Data());
1052 TMap *map = coll->Next();
1054 msg += " using_tags: No (unknown)";
1055 Info("CheckDataType", msg.Data());
1058 map = (TMap*)map->GetValue("");
1060 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1061 use_tags = file.Contains(".tag");
1063 if (use_tags) msg += " using_tags: Yes";
1064 else msg += " using_tags: No";
1065 Info("CheckDataType", msg.Data());
1068 use_tags = slfn.Contains(".tag");
1069 if (slfn.Contains(".root")) msg += " type: root file;";
1070 else msg += " type: unhnown file;";
1071 if (use_tags) msg += " using_tags: Yes";
1072 else msg += " using_tags: No";
1073 Info("CheckDataType", msg.Data());
1076 //______________________________________________________________________________
1077 void AliAnalysisAlien::EnablePackage(const char *package)
1079 // Enables a par file supposed to exist in the current directory.
1080 TString pkg(package);
1081 pkg.ReplaceAll(".par", "");
1083 if (gSystem->AccessPathName(pkg)) {
1084 Error("EnablePackage", "Package %s not found", pkg.Data());
1087 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1088 Info("EnablePackage", "AliEn plugin will use .par packages");
1089 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1091 fPackages = new TObjArray();
1092 fPackages->SetOwner();
1094 fPackages->Add(new TObjString(pkg));
1097 //______________________________________________________________________________
1098 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1100 // Get job status for all jobs with jobid>jobidstart.
1101 static char mstatus[20];
1107 TGridJobStatusList *list = gGrid->Ps("");
1108 if (!list) return mstatus;
1109 Int_t nentries = list->GetSize();
1110 TGridJobStatus *status;
1112 for (Int_t ijob=0; ijob<nentries; ijob++) {
1113 status = (TGridJobStatus *)list->At(ijob);
1114 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1115 if (pid<jobidstart) continue;
1116 if (pid == lastid) {
1117 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1119 switch (status->GetStatus()) {
1120 case TGridJobStatus::kWAITING:
1122 case TGridJobStatus::kRUNNING:
1124 case TGridJobStatus::kABORTED:
1125 case TGridJobStatus::kFAIL:
1126 case TGridJobStatus::kUNKNOWN:
1128 case TGridJobStatus::kDONE:
1137 //______________________________________________________________________________
1138 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1140 // Returns true if file is a collection. Functionality duplicated from
1141 // TAlien::Type() because we don't want to directly depend on TAlien.
1143 Error("IsCollection", "No connection to grid");
1146 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1147 if (!res) return kFALSE;
1148 const char* typeStr = res->GetKey(0, "type");
1149 if (!typeStr || !strlen(typeStr)) return kFALSE;
1150 if (!strcmp(typeStr, "collection")) return kTRUE;
1155 //______________________________________________________________________________
1156 void AliAnalysisAlien::Print(Option_t *) const
1158 // Print current plugin settings.
1159 Printf("### AliEn analysis plugin current settings ###");
1160 Printf("= Production mode:______________________________ %d", fProductionMode);
1161 Printf("= Version of API requested: ____________________ %s", fAPIVersion.Data());
1162 Printf("= Version of ROOT requested: ___________________ %s", fROOTVersion.Data());
1163 Printf("= Version of AliRoot requested: ________________ %s", fAliROOTVersion.Data());
1165 Printf("= User running the plugin: _____________________ %s", fUser.Data());
1166 Printf("= Grid workdir relative to user $HOME: _________ %s", fGridWorkingDir.Data());
1167 Printf("= Grid output directory relative to workdir: ___ %s", fGridOutputDir.Data());
1168 Printf("= Data base directory path requested: __________ %s", fGridDataDir.Data());
1169 Printf("= Data search pattern: _________________________ %s", fDataPattern.Data());
1170 Printf("= Input data format: ___________________________ %s", fInputFormat.Data());
1171 if (fRunNumbers.Length())
1172 Printf("= Run numbers to be processed: _________________ %s", fRunNumbers.Data());
1174 Printf("= Run range to be processed: ___________________ %d-%d", fRunRange[0], fRunRange[1]);
1175 if (!fRunRange[0] && !fRunNumbers.Length()) {
1176 TIter next(fInputFiles);
1179 while ((obj=next())) list += obj->GetName();
1180 Printf("= Input files to be processed: _________________ %s", list.Data());
1182 if (TestBit(AliAnalysisGrid::kTest))
1183 Printf("= Number of input files used in test mode: _____ %d", fNtestFiles);
1184 Printf("= List of output files to be registered: _______ %s", fOutputFiles.Data());
1185 Printf("= List of outputs going to be archived: ________ %s", fOutputArchive.Data());
1186 Printf("= List of outputs that should not be merged: ___ %s", fMergeExcludes.Data());
1187 Printf("=====================================================================");
1188 Printf("= Job price: ___________________________________ %d", fPrice);
1189 Printf("= Time to live (TTL): __________________________ %d", fTTL);
1190 Printf("= Max files per subjob: ________________________ %d", fSplitMaxInputFileNumber);
1191 if (fMaxInitFailed>0)
1192 Printf("= Max number of subjob fails to kill: __________ %d", fMaxInitFailed);
1193 if (fMasterResubmitThreshold>0)
1194 Printf("= Resubmit master job if failed subjobs >_______ %d", fMasterResubmitThreshold);
1195 if (fNrunsPerMaster>0)
1196 Printf("= Number of runs per master job: _______________ %d", fNrunsPerMaster);
1197 Printf("= Number of files in one chunk to be merged: ___ %d", fMaxMergeFiles);
1198 Printf("= Name of the generated execution script: ______ %s",fExecutable.Data());
1199 if (fArguments.Length())
1200 Printf("= Arguments for the execution script: __________ %s",fArguments.Data());
1201 Printf("= Name of the generated analysis macro: ________ %s",fAnalysisMacro.Data());
1202 Printf("= User analysis files to be deployed: __________ %s",fAnalysisSource.Data());
1203 Printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>",fAdditionalLibs.Data());
1204 Printf("= Master jobs split mode: ______________________ %s",fSplitMode.Data());
1206 Printf("= Custom name for the dataset to be created: ___ %s", fDatasetName.Data());
1207 Printf("= Name of the generated JDL: ___________________ %s", fJDLName.Data());
1208 if (fIncludePath.Data())
1209 Printf("= Include path for runtime task compilation: ___ %s", fIncludePath.Data());
1210 if (fCloseSE.Length())
1211 Printf("= Force job outputs to storage element: ________ %s", fCloseSE.Data());
1212 if (fFriendChainName.Length())
1213 Printf("= Open friend chain file on worker: ____________ %s", fFriendChainName.Data());
1215 TIter next(fPackages);
1218 while ((obj=next())) list += obj->GetName();
1219 Printf("= Par files to be used: ________________________ %s", list.Data());
1223 //______________________________________________________________________________
1224 void AliAnalysisAlien::SetDefaults()
1226 // Set default values for everything. What cannot be filled will be left empty.
1227 if (fGridJDL) delete fGridJDL;
1228 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1231 fSplitMaxInputFileNumber = 100;
1233 fMasterResubmitThreshold = 0;
1237 fNrunsPerMaster = 1;
1238 fMaxMergeFiles = 100;
1240 fExecutable = "analysis.sh";
1242 fAnalysisMacro = "myAnalysis.C";
1243 fAnalysisSource = "";
1244 fAdditionalLibs = "";
1248 fAliROOTVersion = "";
1249 fUser = ""; // Your alien user name
1250 fGridWorkingDir = "";
1251 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1252 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1253 fFriendChainName = "";
1254 fGridOutputDir = "output";
1255 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1256 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1257 fInputFormat = "xml-single";
1258 fJDLName = "analysis.jdl";
1259 fJobTag = "Automatically generated analysis JDL";
1260 fMergeExcludes = "";
1263 //______________________________________________________________________________
1264 Bool_t AliAnalysisAlien::MergeOutputs()
1266 // Merge analysis outputs existing in the AliEn space.
1267 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1268 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1270 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1273 // Get the output path
1274 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1275 if (!DirectoryExists(fGridOutputDir)) {
1276 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1279 if (!fOutputFiles.Length()) {
1280 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1283 TObjArray *list = fOutputFiles.Tokenize(" ");
1287 TString output_file;
1288 TString output_chunk;
1289 TString previous_chunk;
1290 Int_t count_chunk = 0;
1291 Int_t count_zero = fMaxMergeFiles;
1292 Bool_t merged = kTRUE;
1293 while((str=(TObjString*)next())) {
1294 output_file = str->GetString();
1295 Int_t index = output_file.Index("@");
1296 if (index > 0) output_file.Remove(index);
1297 // Skip already merged outputs
1298 if (!gSystem->AccessPathName(output_file)) {
1299 Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1302 if (fMergeExcludes.Length() &&
1303 fMergeExcludes.Contains(output_file.Data())) continue;
1304 // Perform a 'find' command in the output directory, looking for registered outputs
1305 command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1306 Printf("command: %s", command.Data());
1307 TGridResult *res = gGrid->Command(command);
1309 TFileMerger *fm = 0;
1312 previous_chunk = "";
1314 // Check if there is a merge operation to resume
1315 output_chunk = output_file;
1316 output_chunk.ReplaceAll(".root", "_*.root");
1317 if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1319 for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1321 Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1325 output_chunk = output_file;
1326 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1327 Printf("%s", output_chunk.Data());
1329 if (gSystem->AccessPathName(output_chunk)) continue;
1330 // Merged file with chunks up to <count_chunk> found
1331 Printf("Resume merging of <%s> from <%s>", output_file.Data(), output_chunk.Data());
1332 previous_chunk = output_chunk;
1336 count_zero = fMaxMergeFiles;
1337 while ((map=(TMap*)nextmap())) {
1338 // Loop 'find' results and get next LFN
1339 if (count_zero == fMaxMergeFiles) {
1340 // First file in chunk - create file merger and add previous chunk if any.
1341 fm = new TFileMerger(kFALSE);
1342 fm->SetFastMethod(kTRUE);
1343 if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1344 output_chunk = output_file;
1345 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1347 // If last file found, put merged results in the output file
1348 if (map == res->Last()) output_chunk = output_file;
1349 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1350 if (!objs || !objs->GetString().Length()) {
1351 // Nothing found - skip this output
1356 // Add file to be merged and decrement chunk counter.
1357 fm->AddFile(objs->GetString());
1359 if (count_zero==0 || map == res->Last()) {
1360 fm->OutputFile(output_chunk);
1361 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1362 // Nothing found - skip this output
1363 Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1368 // Merge the outputs, then go to next chunk
1370 Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1376 Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1377 gSystem->Unlink(previous_chunk);
1379 if (map == res->Last()) {
1385 count_zero = fMaxMergeFiles;
1386 previous_chunk = output_chunk;
1391 Error("MergeOutputs", "Terminate() will NOT be executed");
1396 //______________________________________________________________________________
1397 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1399 // Use the output files connected to output containers from the analysis manager
1400 // rather than the files defined by SetOutputFiles
1401 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1402 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1404 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1407 //______________________________________________________________________________
1408 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1410 // Start remote grid analysis.
1412 // Check if output files have to be taken from the analysis manager
1413 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1414 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1415 if (!mgr || !mgr->IsInitialized()) {
1416 Error("StartAnalysis", "You need an initialized analysis manager for this");
1420 TIter next(mgr->GetOutputs());
1421 AliAnalysisDataContainer *output;
1422 while ((output=(AliAnalysisDataContainer*)next())) {
1423 const char *filename = output->GetFileName();
1424 if (!(strcmp(filename, "default"))) {
1425 if (!mgr->GetOutputEventHandler()) continue;
1426 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1428 if (fOutputFiles.Length()) fOutputFiles += " ";
1429 fOutputFiles += filename;
1431 // Add extra files registered to the analysis manager
1432 if (mgr->GetExtraFiles().Length()) {
1433 if (fOutputFiles.Length()) fOutputFiles += " ";
1434 fOutputFiles += mgr->GetExtraFiles();
1437 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1438 if (TestBit(AliAnalysisGrid::kOffline)) {
1439 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1440 \n there nor any job run. You can revise the JDL and analysis \
1441 \n macro then run the same in \"submit\" mode.");
1442 } else if (TestBit(AliAnalysisGrid::kTest)) {
1443 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1445 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1446 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1447 \n space and job submitted.");
1448 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1449 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1452 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1456 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1460 if (!CheckInputData()) {
1461 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1464 CreateDataset(fDataPattern);
1465 WriteAnalysisFile();
1466 WriteAnalysisMacro();
1468 WriteValidationScript();
1469 if (!CreateJDL()) return kFALSE;
1470 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1471 if (TestBit(AliAnalysisGrid::kTest)) {
1472 // Locally testing the analysis
1473 Info("StartAnalysis", "\n_______________________________________________________________________ \
1474 \n Running analysis script in a daughter shell as on a worker node \
1475 \n_______________________________________________________________________");
1476 TObjArray *list = fOutputFiles.Tokenize(" ");
1479 TString output_file;
1480 while((str=(TObjString*)next())) {
1481 output_file = str->GetString();
1482 Int_t index = output_file.Index("@");
1483 if (index > 0) output_file.Remove(index);
1484 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1487 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1488 TString validationScript = fExecutable;
1489 validationScript.ReplaceAll(".sh", "_validation.sh");
1490 gSystem->Exec(Form("bash %s",validationScript.Data()));
1491 // gSystem->Exec("cat stdout");
1494 // Check if submitting is managed by LPM manager
1495 if (fProductionMode) {
1496 TString prodfile = fJDLName;
1497 prodfile.ReplaceAll(".jdl", ".prod");
1498 WriteProductionFile(prodfile);
1499 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1502 // Submit AliEn job(s)
1503 gGrid->Cd(fGridOutputDir);
1506 if (!fRunNumbers.Length() && !fRunRange[0]) {
1507 // Submit a given xml or a set of runs
1508 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1509 Printf("*************************** %s",Form("submit %s", fJDLName.Data()));
1511 const char *cjobId = res->GetKey(0,"jobId");
1513 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1516 Info("StartAnalysis", "\n_______________________________________________________________________ \
1517 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1518 \n_______________________________________________________________________",
1519 fJDLName.Data(), cjobId);
1525 // Submit for a range of enumeration of runs.
1529 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1530 \n You may exit at any time and terminate the job later using the option <terminate> \
1531 \n ##################################################################################", jobID.Data());
1532 gSystem->Exec("aliensh");
1536 //______________________________________________________________________________
1537 void AliAnalysisAlien::Submit()
1539 // Submit all master jobs.
1540 Int_t nmasterjobs = fInputFiles->GetEntries();
1541 Long_t tshoot = gSystem->Now();
1542 if (!fNsubmitted) SubmitNext();
1543 while (fNsubmitted < nmasterjobs) {
1544 Long_t now = gSystem->Now();
1545 if ((now-tshoot)>30000) {
1552 //______________________________________________________________________________
1553 void AliAnalysisAlien::SubmitNext()
1555 // Submit next bunch of master jobs if the queue is free.
1556 static Bool_t iscalled = kFALSE;
1557 static Int_t firstmaster = 0;
1558 static Int_t lastmaster = 0;
1559 static Int_t npermaster = 0;
1560 if (iscalled) return;
1562 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1563 Int_t ntosubmit = 0;
1566 if (!fNsubmitted) ntosubmit = 1;
1568 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1569 Printf("=== master %d: %s", lastmaster, status.Data());
1570 // If last master not split, just return
1571 if (status != "SPLIT") {iscalled = kFALSE; return;}
1572 // No more than 100 waiting jobs
1573 if (nwaiting>100) {iscalled = kFALSE; return;}
1574 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
1575 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1576 Printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs",
1577 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1579 Int_t nmasterjobs = fInputFiles->GetEntries();
1580 for (Int_t i=0; i<ntosubmit; i++) {
1581 // Submit for a range of enumeration of runs.
1582 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1584 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1585 Printf("********* %s",query.Data());
1586 res = gGrid->Command(query);
1588 TString cjobId1 = res->GetKey(0,"jobId");
1589 if (!cjobId1.Length()) {
1590 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1594 Info("StartAnalysis", "\n_______________________________________________________________________ \
1595 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1596 \n_______________________________________________________________________",
1597 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1600 lastmaster = cjobId1.Atoi();
1601 if (!firstmaster) firstmaster = lastmaster;
1610 //______________________________________________________________________________
1611 void AliAnalysisAlien::WriteAnalysisFile()
1613 // Write current analysis manager into the file <analysisFile>
1614 TString analysisFile = fExecutable;
1615 analysisFile.ReplaceAll(".sh", ".root");
1616 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1617 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1618 if (!mgr || !mgr->IsInitialized()) {
1619 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1622 // Check analysis type
1624 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1625 handler = (TObject*)mgr->GetInputEventHandler();
1627 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1628 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1630 TDirectory *cdir = gDirectory;
1631 TFile *file = TFile::Open(analysisFile, "RECREATE");
1636 if (cdir) cdir->cd();
1637 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1639 Bool_t copy = kTRUE;
1640 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1643 TString workdir = gGrid->GetHomeDirectory();
1644 workdir += fGridWorkingDir;
1645 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1646 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1647 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1651 //______________________________________________________________________________
1652 void AliAnalysisAlien::WriteAnalysisMacro()
1654 // Write the analysis macro that will steer the analysis in grid mode.
1655 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1657 out.open(fAnalysisMacro.Data(), ios::out);
1659 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1662 TString func = fAnalysisMacro;
1663 TString type = "ESD";
1664 TString comment = "// Analysis using ";
1665 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1666 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1670 if (type!="AOD" && fFriendChainName!="") {
1671 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1674 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1675 else comment += " data";
1676 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1677 func.ReplaceAll(".C", "");
1678 out << "void " << func.Data() << "()" << endl;
1680 out << comment.Data() << endl;
1681 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1682 out << " TStopwatch timer;" << endl;
1683 out << " timer.Start();" << endl << endl;
1684 out << "// load base root libraries" << endl;
1685 out << " gSystem->Load(\"libTree\");" << endl;
1686 out << " gSystem->Load(\"libGeom\");" << endl;
1687 out << " gSystem->Load(\"libVMC\");" << endl;
1688 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
1689 out << "// Load analysis framework libraries" << endl;
1691 out << " gSystem->Load(\"libSTEERBase\");" << endl;
1692 out << " gSystem->Load(\"libESD\");" << endl;
1693 out << " gSystem->Load(\"libAOD\");" << endl;
1694 out << " gSystem->Load(\"libANALYSIS\");" << endl;
1695 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1696 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1698 TIter next(fPackages);
1701 Bool_t hasSTEERBase = kFALSE;
1702 Bool_t hasESD = kFALSE;
1703 Bool_t hasAOD = kFALSE;
1704 Bool_t hasANALYSIS = kFALSE;
1705 Bool_t hasANALYSISalice = kFALSE;
1706 Bool_t hasCORRFW = kFALSE;
1707 while ((obj=next())) {
1708 pkgname = obj->GetName();
1709 if (pkgname == "STEERBase" ||
1710 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1711 if (pkgname == "ESD" ||
1712 pkgname == "ESD.par") hasESD = kTRUE;
1713 if (pkgname == "AOD" ||
1714 pkgname == "AOD.par") hasAOD = kTRUE;
1715 if (pkgname == "ANALYSIS" ||
1716 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
1717 if (pkgname == "ANALYSISalice" ||
1718 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1719 if (pkgname == "CORRFW" ||
1720 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
1722 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
1723 else out << " if (!SetupPar(\"STEERBase\")) return;" << endl;
1724 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
1725 else out << " if (!SetupPar(\"ESD\")) return;" << endl;
1726 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
1727 else out << " if (!SetupPar(\"AOD\")) return;" << endl;
1728 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
1729 else out << " if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1730 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
1731 else out << " if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1732 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
1733 else out << " if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1734 out << "// Compile other par packages" << endl;
1736 while ((obj=next())) {
1737 pkgname = obj->GetName();
1738 if (pkgname == "STEERBase" ||
1739 pkgname == "STEERBase.par" ||
1741 pkgname == "ESD.par" ||
1743 pkgname == "AOD.par" ||
1744 pkgname == "ANALYSIS" ||
1745 pkgname == "ANALYSIS.par" ||
1746 pkgname == "ANALYSISalice" ||
1747 pkgname == "ANALYSISalice.par" ||
1748 pkgname == "CORRFW" ||
1749 pkgname == "CORRFW.par") continue;
1750 out << " if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1753 out << "// include path" << endl;
1754 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1755 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1756 if (fAdditionalLibs.Length()) {
1757 out << "// Add aditional AliRoot libraries" << endl;
1758 TObjArray *list = fAdditionalLibs.Tokenize(" ");
1761 while((str=(TObjString*)next())) {
1762 if (str->GetString().Contains(".so"))
1763 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1765 if (list) delete list;
1768 out << "// analysis source to be compiled at runtime (if any)" << endl;
1769 if (fAnalysisSource.Length()) {
1770 TObjArray *list = fAnalysisSource.Tokenize(" ");
1773 while((str=(TObjString*)next())) {
1774 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1776 if (list) delete list;
1779 out << "// connect to AliEn and make the chain" << endl;
1780 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
1781 if (IsUsingTags()) {
1782 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1784 if(fFriendChainName!="AliAOD.VertexingHF.root") {
1785 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
1787 out << " // Check if the macro to create the chain was provided" << endl;
1788 out << " if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1789 out << " ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1790 out << " return;" << endl;
1791 out << " }" << endl;
1792 out << " gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1793 out << " TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1796 out << "// read the analysis manager from file" << endl;
1797 TString analysisFile = fExecutable;
1798 analysisFile.ReplaceAll(".sh", ".root");
1799 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1800 out << " if (!file) return;" << endl;
1801 out << " TIter nextkey(file->GetListOfKeys());" << endl;
1802 out << " AliAnalysisManager *mgr = 0;" << endl;
1803 out << " TKey *key;" << endl;
1804 out << " while ((key=(TKey*)nextkey())) {" << endl;
1805 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1806 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1807 out << " };" << endl;
1808 out << " if (!mgr) {" << endl;
1809 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1810 out << " return;" << endl;
1811 out << " }" << endl << endl;
1812 out << " mgr->PrintStatus();" << endl;
1813 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
1814 out << " timer.Stop();" << endl;
1815 out << " timer.Print();" << endl;
1816 out << "}" << endl << endl;
1817 if (IsUsingTags()) {
1818 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1820 out << "// Create a chain using tags from the xml file." << endl;
1821 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1822 out << " if (!coll) {" << endl;
1823 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1824 out << " return NULL;" << endl;
1825 out << " }" << endl;
1826 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1827 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1828 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
1829 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
1830 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
1831 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1832 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
1833 out << " // Check if the cuts configuration file was provided" << endl;
1834 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1835 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1836 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1837 out << " }" << endl;
1838 if (fFriendChainName=="") {
1839 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1841 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
1842 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1843 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1845 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1846 out << " chain->ls();" << endl;
1847 out << " return chain;" << endl;
1848 out << "}" << endl << endl;
1849 if (gSystem->AccessPathName("ConfigureCuts.C")) {
1850 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
1851 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1852 msg += " AliLHCTagCuts *lhcCuts,\n";
1853 msg += " AliDetectorTagCuts *detCuts,\n";
1854 msg += " AliEventTagCuts *evCuts)";
1855 Info("WriteAnalysisMacro", msg.Data());
1858 if (!IsUsingTags() || fFriendChainName!="") {
1859 out <<"//________________________________________________________________________________" << endl;
1860 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1862 out << "// Create a chain using url's from xml file" << endl;
1863 out << " TString treename = type;" << endl;
1864 out << " treename.ToLower();" << endl;
1865 out << " treename += \"Tree\";" << endl;
1866 out << " printf(\"***************************************\\n\");" << endl;
1867 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
1868 out << " printf(\"***************************************\\n\");" << endl;
1869 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1870 out << " if (!coll) {" << endl;
1871 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1872 out << " return NULL;" << endl;
1873 out << " }" << endl;
1874 out << " TChain *chain = new TChain(treename);" << endl;
1875 if(fFriendChainName!="") {
1876 out << " TChain *chainFriend = new TChain(treename);" << endl;
1878 out << " coll->Reset();" << endl;
1879 out << " while (coll->Next()) {" << endl;
1880 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
1881 if(fFriendChainName!="") {
1882 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
1883 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1884 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1885 out << " chainFriend->Add(fileFriend.Data());" << endl;
1887 out << " }" << endl;
1888 out << " if (!chain->GetNtrees()) {" << endl;
1889 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1890 out << " return NULL;" << endl;
1891 out << " }" << endl;
1892 if(fFriendChainName!="") {
1893 out << " chain->AddFriend(chainFriend);" << endl;
1895 out << " return chain;" << endl;
1896 out << "}" << endl << endl;
1899 out <<"//________________________________________________________________________________" << endl;
1900 out << "Bool_t SetupPar(const char *package) {" << endl;
1901 out << "// Compile the package and set it up." << endl;
1902 out << " TString pkgdir = package;" << endl;
1903 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1904 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1905 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
1906 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
1907 out << " // Check for BUILD.sh and execute" << endl;
1908 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1909 out << " printf(\"*******************************\\n\");" << endl;
1910 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
1911 out << " printf(\"*******************************\\n\");" << endl;
1912 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1913 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1914 out << " gSystem->ChangeDirectory(cdir);" << endl;
1915 out << " return kFALSE;" << endl;
1916 out << " }" << endl;
1917 out << " } else {" << endl;
1918 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1919 out << " gSystem->ChangeDirectory(cdir);" << endl;
1920 out << " return kFALSE;" << endl;
1921 out << " }" << endl;
1922 out << " // Check for SETUP.C and execute" << endl;
1923 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1924 out << " printf(\"*******************************\\n\");" << endl;
1925 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
1926 out << " printf(\"*******************************\\n\");" << endl;
1927 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1928 out << " } else {" << endl;
1929 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1930 out << " gSystem->ChangeDirectory(cdir);" << endl;
1931 out << " return kFALSE;" << endl;
1932 out << " }" << endl;
1933 out << " // Restore original workdir" << endl;
1934 out << " gSystem->ChangeDirectory(cdir);" << endl;
1935 out << " return kTRUE;" << endl;
1938 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1940 Bool_t copy = kTRUE;
1941 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1944 TString workdir = gGrid->GetHomeDirectory();
1945 workdir += fGridWorkingDir;
1946 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1947 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1948 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1949 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1950 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1952 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1953 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1957 //______________________________________________________________________________
1958 void AliAnalysisAlien::WriteExecutable()
1960 // Generate the alien executable script.
1961 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1963 out.open(fExecutable.Data(), ios::out);
1965 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
1968 out << "#!/bin/bash" << endl;
1969 out << "echo \"=========================================\"" << endl;
1970 out << "echo \"############## PATH : ##############\"" << endl;
1971 out << "echo $PATH" << endl;
1972 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1973 out << "echo $LD_LIBRARY_PATH" << endl;
1974 out << "echo \"############## ROOTSYS : ##############\"" << endl;
1975 out << "echo $ROOTSYS" << endl;
1976 out << "echo \"############## which root : ##############\"" << endl;
1977 out << "which root" << endl;
1978 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1979 out << "echo $ALICE_ROOT" << endl;
1980 out << "echo \"############## which aliroot : ##############\"" << endl;
1981 out << "which aliroot" << endl;
1982 out << "echo \"=========================================\"" << endl << endl;
1983 // if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1984 out << "root -b -q ";
1985 out << fAnalysisMacro.Data() << endl << endl;
1986 out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1988 Bool_t copy = kTRUE;
1989 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1992 TString workdir = gGrid->GetHomeDirectory();
1993 TString bindir = Form("%s/bin", workdir.Data());
1994 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
1995 workdir += fGridWorkingDir;
1996 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1997 if (FileExists(executable)) gGrid->Rm(executable);
1998 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1999 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2003 //______________________________________________________________________________
2004 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2006 // Write the production file to be submitted by LPM manager. The format is:
2007 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2008 // Next lines: full_path_to_dataset XXX (XXX is a string)
2009 // To submit, one has to: submit jdl XXX for all lines
2011 out.open(filename, ios::out);
2013 Error("WriteProductionFile", "Bad file name: %s", filename);
2016 TString workdir = gGrid->GetHomeDirectory();
2017 workdir += fGridWorkingDir;
2018 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2019 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2020 out << locjdl << " " << njobspermaster << endl;
2021 Int_t nmasterjobs = fInputFiles->GetEntries();
2022 for (Int_t i=0; i<nmasterjobs; i++) {
2023 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2025 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
2026 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
2029 //______________________________________________________________________________
2030 void AliAnalysisAlien::WriteValidationScript()
2032 // Generate the alien validation script.
2033 // Generate the validation script
2035 TString validationScript = fExecutable;
2036 validationScript.ReplaceAll(".sh", "_validation.sh");
2038 Error("WriteValidationScript", "Alien connection required");
2041 TString out_stream = "";
2042 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2043 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2045 out.open(validationScript, ios::out);
2046 out << "#!/bin/bash" << endl;
2047 out << "##################################################" << endl;
2048 out << "validateout=`dirname $0`" << endl;
2049 out << "validatetime=`date`" << endl;
2050 out << "validated=\"0\";" << endl;
2051 out << "error=0" << endl;
2052 out << "if [ -z $validateout ]" << endl;
2053 out << "then" << endl;
2054 out << " validateout=\".\"" << endl;
2055 out << "fi" << endl << endl;
2056 out << "cd $validateout;" << endl;
2057 out << "validateworkdir=`pwd`;" << endl << endl;
2058 out << "echo \"*******************************************************\"" << out_stream << endl;
2059 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
2061 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
2062 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
2063 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
2064 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2065 out << "ls -la ./" << out_stream << endl;
2066 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
2067 out << "##################################################" << endl;
2070 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2071 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2072 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2075 out << "if [ ! -f stderr ] ; then" << endl;
2076 out << " error=1" << endl;
2077 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
2078 out << " echo \"Error = $error\" " << out_stream << endl;
2079 out << "fi" << endl;
2081 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2082 out << " error=1" << endl;
2083 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
2084 out << " echo \"$parArch\" " << out_stream << endl;
2085 out << " echo \"Error = $error\" " << out_stream << endl;
2086 out << "fi" << endl;
2088 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2089 out << " error=1" << endl;
2090 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
2091 out << " echo \"$segViol\" " << out_stream << endl;
2092 out << " echo \"Error = $error\" " << out_stream << endl;
2093 out << "fi" << endl;
2095 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2096 out << " error=1" << endl;
2097 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
2098 out << " echo \"$segFault\" " << out_stream << endl;
2099 out << " echo \"Error = $error\" " << out_stream << endl;
2100 out << "fi" << endl;
2102 // Part dedicated to the specific analyses running into the train
2104 TObjArray *arr = fOutputFiles.Tokenize(" ");
2106 TString output_file;
2107 while ((os=(TObjString*)next1())) {
2108 output_file = os->GetString();
2109 Int_t index = output_file.Index("@");
2110 if (index > 0) output_file.Remove(index);
2111 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2112 out << " error=1" << endl;
2113 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
2114 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2115 out << "fi" << endl;
2118 out << "if ! [ -f outputs_valid ] ; then" << endl;
2119 out << " error=1" << endl;
2120 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2121 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2122 out << "fi" << endl;
2124 out << "if [ $error = 0 ] ; then" << endl;
2125 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
2126 out << "fi" << endl;
2128 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2129 out << "echo \"*******************************************************\"" << out_stream << endl;
2130 out << "cd -" << endl;
2131 out << "exit $error" << endl;
2133 Bool_t copy = kTRUE;
2134 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2137 TString workdir = gGrid->GetHomeDirectory();
2138 workdir += fGridWorkingDir;
2139 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
2140 if (FileExists(validationScript)) gGrid->Rm(validationScript);
2141 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));