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"
30 #include "TFileCollection.h"
32 #include "TObjString.h"
33 #include "TObjArray.h"
35 #include "TGridResult.h"
36 #include "TGridCollection.h"
38 #include "TGridJobStatusList.h"
39 #include "TGridJobStatus.h"
40 #include "TFileMerger.h"
41 #include "AliAnalysisManager.h"
42 #include "AliVEventHandler.h"
43 #include "AliAnalysisDataContainer.h"
44 #include "AliAnalysisAlien.h"
46 ClassImp(AliAnalysisAlien)
48 //______________________________________________________________________________
49 AliAnalysisAlien::AliAnalysisAlien()
55 fSplitMaxInputFileNumber(0),
57 fMasterResubmitThreshold(0),
70 fNproofWorkersPerSlave(0),
80 fAdditionalRootLibs(),
108 fRootVersionForProof(),
117 //______________________________________________________________________________
118 AliAnalysisAlien::AliAnalysisAlien(const char *name)
119 :AliAnalysisGrid(name),
124 fSplitMaxInputFileNumber(0),
126 fMasterResubmitThreshold(0),
139 fNproofWorkersPerSlave(0),
143 fExecutableCommand(),
149 fAdditionalRootLibs(),
177 fRootVersionForProof(),
186 //______________________________________________________________________________
187 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
188 :AliAnalysisGrid(other),
191 fPrice(other.fPrice),
193 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
194 fMaxInitFailed(other.fMaxInitFailed),
195 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
196 fNtestFiles(other.fNtestFiles),
197 fNrunsPerMaster(other.fNrunsPerMaster),
198 fMaxMergeFiles(other.fMaxMergeFiles),
199 fMaxMergeStages(other.fMaxMergeStages),
200 fNsubmitted(other.fNsubmitted),
201 fProductionMode(other.fProductionMode),
202 fOutputToRunNo(other.fOutputToRunNo),
203 fMergeViaJDL(other.fMergeViaJDL),
204 fFastReadOption(other.fFastReadOption),
205 fOverwriteMode(other.fOverwriteMode),
206 fNreplicas(other.fNreplicas),
207 fNproofWorkers(other.fNproofWorkers),
208 fNproofWorkersPerSlave(other.fNproofWorkersPerSlave),
209 fProofReset(other.fProofReset),
210 fRunNumbers(other.fRunNumbers),
211 fExecutable(other.fExecutable),
212 fExecutableCommand(other.fExecutableCommand),
213 fArguments(other.fArguments),
214 fExecutableArgs(other.fExecutableArgs),
215 fAnalysisMacro(other.fAnalysisMacro),
216 fAnalysisSource(other.fAnalysisSource),
217 fValidationScript(other.fValidationScript),
218 fAdditionalRootLibs(other.fAdditionalRootLibs),
219 fAdditionalLibs(other.fAdditionalLibs),
220 fSplitMode(other.fSplitMode),
221 fAPIVersion(other.fAPIVersion),
222 fROOTVersion(other.fROOTVersion),
223 fAliROOTVersion(other.fAliROOTVersion),
224 fExternalPackages(other.fExternalPackages),
226 fGridWorkingDir(other.fGridWorkingDir),
227 fGridDataDir(other.fGridDataDir),
228 fDataPattern(other.fDataPattern),
229 fGridOutputDir(other.fGridOutputDir),
230 fOutputArchive(other.fOutputArchive),
231 fOutputFiles(other.fOutputFiles),
232 fInputFormat(other.fInputFormat),
233 fDatasetName(other.fDatasetName),
234 fJDLName(other.fJDLName),
235 fTerminateFiles(other.fTerminateFiles),
236 fMergeExcludes(other.fMergeExcludes),
237 fIncludePath(other.fIncludePath),
238 fCloseSE(other.fCloseSE),
239 fFriendChainName(other.fFriendChainName),
240 fJobTag(other.fJobTag),
241 fOutputSingle(other.fOutputSingle),
242 fRunPrefix(other.fRunPrefix),
243 fProofCluster(other.fProofCluster),
244 fProofDataSet(other.fProofDataSet),
245 fFileForTestMode(other.fFileForTestMode),
246 fRootVersionForProof(other.fRootVersionForProof),
247 fAliRootMode(other.fAliRootMode),
252 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
253 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
254 fRunRange[0] = other.fRunRange[0];
255 fRunRange[1] = other.fRunRange[1];
256 if (other.fInputFiles) {
257 fInputFiles = new TObjArray();
258 TIter next(other.fInputFiles);
260 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
261 fInputFiles->SetOwner();
263 if (other.fPackages) {
264 fPackages = new TObjArray();
265 TIter next(other.fPackages);
267 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
268 fPackages->SetOwner();
272 //______________________________________________________________________________
273 AliAnalysisAlien::~AliAnalysisAlien()
276 if (fGridJDL) delete fGridJDL;
277 if (fMergingJDL) delete fMergingJDL;
278 if (fInputFiles) delete fInputFiles;
279 if (fPackages) delete fPackages;
282 //______________________________________________________________________________
283 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
286 if (this != &other) {
287 AliAnalysisGrid::operator=(other);
288 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
289 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
290 fPrice = other.fPrice;
292 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
293 fMaxInitFailed = other.fMaxInitFailed;
294 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
295 fNtestFiles = other.fNtestFiles;
296 fNrunsPerMaster = other.fNrunsPerMaster;
297 fMaxMergeFiles = other.fMaxMergeFiles;
298 fMaxMergeStages = other.fMaxMergeStages;
299 fNsubmitted = other.fNsubmitted;
300 fProductionMode = other.fProductionMode;
301 fOutputToRunNo = other.fOutputToRunNo;
302 fMergeViaJDL = other.fMergeViaJDL;
303 fFastReadOption = other.fFastReadOption;
304 fOverwriteMode = other.fOverwriteMode;
305 fNreplicas = other.fNreplicas;
306 fNproofWorkers = other.fNproofWorkers;
307 fNproofWorkersPerSlave = other.fNproofWorkersPerSlave;
308 fProofReset = other.fProofReset;
309 fRunNumbers = other.fRunNumbers;
310 fExecutable = other.fExecutable;
311 fExecutableCommand = other.fExecutableCommand;
312 fArguments = other.fArguments;
313 fExecutableArgs = other.fExecutableArgs;
314 fAnalysisMacro = other.fAnalysisMacro;
315 fAnalysisSource = other.fAnalysisSource;
316 fValidationScript = other.fValidationScript;
317 fAdditionalRootLibs = other.fAdditionalRootLibs;
318 fAdditionalLibs = other.fAdditionalLibs;
319 fSplitMode = other.fSplitMode;
320 fAPIVersion = other.fAPIVersion;
321 fROOTVersion = other.fROOTVersion;
322 fAliROOTVersion = other.fAliROOTVersion;
323 fExternalPackages = other.fExternalPackages;
325 fGridWorkingDir = other.fGridWorkingDir;
326 fGridDataDir = other.fGridDataDir;
327 fDataPattern = other.fDataPattern;
328 fGridOutputDir = other.fGridOutputDir;
329 fOutputArchive = other.fOutputArchive;
330 fOutputFiles = other.fOutputFiles;
331 fInputFormat = other.fInputFormat;
332 fDatasetName = other.fDatasetName;
333 fJDLName = other.fJDLName;
334 fTerminateFiles = other.fTerminateFiles;
335 fMergeExcludes = other.fMergeExcludes;
336 fIncludePath = other.fIncludePath;
337 fCloseSE = other.fCloseSE;
338 fFriendChainName = other.fFriendChainName;
339 fJobTag = other.fJobTag;
340 fOutputSingle = other.fOutputSingle;
341 fRunPrefix = other.fRunPrefix;
342 fProofCluster = other.fProofCluster;
343 fProofDataSet = other.fProofDataSet;
344 fFileForTestMode = other.fFileForTestMode;
345 fRootVersionForProof = other.fRootVersionForProof;
346 fAliRootMode = other.fAliRootMode;
347 if (other.fInputFiles) {
348 fInputFiles = new TObjArray();
349 TIter next(other.fInputFiles);
351 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
352 fInputFiles->SetOwner();
354 if (other.fPackages) {
355 fPackages = new TObjArray();
356 TIter next(other.fPackages);
358 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
359 fPackages->SetOwner();
365 //______________________________________________________________________________
366 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
368 // Set the run number format. Can be a prefix or a format like "%09d"
370 if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
373 //______________________________________________________________________________
374 void AliAnalysisAlien::AddIncludePath(const char *path)
376 // Add include path in the remote analysis macro.
378 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
379 else fIncludePath += Form("-I%s ", path);
382 //______________________________________________________________________________
383 void AliAnalysisAlien::AddRunNumber(Int_t run)
385 // Add a run number to the list of runs to be processed.
386 if (fRunNumbers.Length()) fRunNumbers += " ";
387 fRunNumbers += Form(fRunPrefix.Data(), run);
390 //______________________________________________________________________________
391 void AliAnalysisAlien::AddRunNumber(const char* run)
393 // Add a run number to the list of runs to be processed.
394 if (fRunNumbers.Length()) fRunNumbers += " ";
398 //______________________________________________________________________________
399 void AliAnalysisAlien::AddDataFile(const char *lfn)
401 // Adds a data file to the input to be analysed. The file should be a valid LFN
402 // or point to an existing file in the alien workdir.
403 if (!fInputFiles) fInputFiles = new TObjArray();
404 fInputFiles->Add(new TObjString(lfn));
407 //______________________________________________________________________________
408 void AliAnalysisAlien::AddExternalPackage(const char *package)
410 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
411 if (fExternalPackages) fExternalPackages += " ";
412 fExternalPackages += package;
415 //______________________________________________________________________________
416 Bool_t AliAnalysisAlien::Connect()
418 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
419 if (gGrid && gGrid->IsConnected()) return kTRUE;
420 if (fProductionMode) return kTRUE;
422 Info("Connect", "Trying to connect to AliEn ...");
423 TGrid::Connect("alien://");
425 if (!gGrid || !gGrid->IsConnected()) {
426 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
429 fUser = gGrid->GetUser();
430 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
434 //______________________________________________________________________________
435 void AliAnalysisAlien::CdWork()
437 // Check validity of alien workspace. Create directory if possible.
439 Error("CdWork", "Alien connection required");
442 TString homedir = gGrid->GetHomeDirectory();
443 TString workdir = homedir + fGridWorkingDir;
444 if (DirectoryExists(workdir)) {
448 // Work directory not existing - create it
450 if (gGrid->Mkdir(workdir, "-p")) {
451 gGrid->Cd(fGridWorkingDir);
452 Info("CdWork", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
454 Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
455 workdir.Data(), homedir.Data());
456 fGridWorkingDir = "";
460 //______________________________________________________________________________
461 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
463 // Check if file copying is possible.
464 if (fProductionMode) return kTRUE;
466 Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
469 Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
470 \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
471 // Check if alien_CLOSE_SE is defined
472 TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
473 if (!closeSE.IsNull()) {
474 Info("CheckFileCopy", "Your current close storage is pointing to: \
475 \n alien_CLOSE_SE = \"%s\"", closeSE.Data());
477 Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
479 // Check if grid directory exists.
480 if (!DirectoryExists(alienpath)) {
481 Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
484 TFile f("plugin_test_copy", "RECREATE");
485 // User may not have write permissions to current directory
487 Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
488 gSystem->WorkingDirectory());
492 if (FileExists(Form("alien://%s/%s",alienpath, f.GetName()))) gGrid->Rm(Form("alien://%s/%s",alienpath, f.GetName()));
493 if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, f.GetName()))) {
494 Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
495 \n# 1. Make sure you have write permissions there. If this is the case: \
496 \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
497 \n# Do: export alien_CLOSE_SE=\"working_disk_SE\" \
498 \n# To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
499 \n# Redo token: rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
500 gSystem->Unlink(f.GetName());
503 gSystem->Unlink(f.GetName());
504 gGrid->Rm(Form("%s%s",alienpath,f.GetName()));
505 Info("CheckFileCopy", "### ...SUCCESS ###");
509 //______________________________________________________________________________
510 Bool_t AliAnalysisAlien::CheckInputData()
512 // Check validity of input data. If necessary, create xml files.
513 if (fProductionMode) return kTRUE;
514 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
515 if (!fGridDataDir.Length()) {
516 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
519 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
520 if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
521 TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode)
524 // Process declared files
525 Bool_t isCollection = kFALSE;
526 Bool_t isXml = kFALSE;
527 Bool_t useTags = kFALSE;
528 Bool_t checked = kFALSE;
529 if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
531 TString workdir = gGrid->GetHomeDirectory();
532 workdir += fGridWorkingDir;
535 TIter next(fInputFiles);
536 while ((objstr=(TObjString*)next())) {
539 file += objstr->GetString();
540 // Store full lfn path
541 if (FileExists(file)) objstr->SetString(file);
543 file = objstr->GetName();
544 if (!FileExists(objstr->GetName())) {
545 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
546 objstr->GetName(), workdir.Data());
550 Bool_t iscoll, isxml, usetags;
551 CheckDataType(file, iscoll, isxml, usetags);
554 isCollection = iscoll;
557 TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
559 if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
560 Error("CheckInputData", "Some conflict was found in the types of inputs");
566 // Process requested run numbers
567 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
568 // Check validity of alien data directory
569 if (!fGridDataDir.Length()) {
570 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
573 if (!DirectoryExists(fGridDataDir)) {
574 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
578 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
582 if (checked && !isXml) {
583 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
586 // Check validity of run number(s)
591 TString schunk, schunk2;
595 useTags = fDataPattern.Contains("tag");
596 TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
598 if (useTags != fDataPattern.Contains("tag")) {
599 Error("CheckInputData", "Cannot mix input files using/not using tags");
602 if (fRunNumbers.Length()) {
603 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
604 arr = fRunNumbers.Tokenize(" ");
606 while ((os=(TObjString*)next())) {
607 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
608 if (!DirectoryExists(path)) {
609 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
612 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
613 TString msg = "\n##### file: ";
615 msg += " type: xml_collection;";
616 if (useTags) msg += " using_tags: Yes";
617 else msg += " using_tags: No";
618 Info("CheckDataType", "%s", msg.Data());
619 if (fNrunsPerMaster<2) {
620 AddDataFile(Form("%s.xml", os->GetString().Data()));
623 if (((nruns-1)%fNrunsPerMaster) == 0) {
624 schunk = os->GetString();
626 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
627 schunk += Form("_%s.xml", os->GetString().Data());
633 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
634 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
635 format = Form("%%s/%s ", fRunPrefix.Data());
636 path = Form(format.Data(), fGridDataDir.Data(), irun);
637 if (!DirectoryExists(path)) {
640 format = Form("%%s/%s.xml", fRunPrefix.Data());
641 path = Form(format.Data(), workdir.Data(),irun);
642 TString msg = "\n##### file: ";
644 msg += " type: xml_collection;";
645 if (useTags) msg += " using_tags: Yes";
646 else msg += " using_tags: No";
647 Info("CheckDataType", "%s", msg.Data());
648 if (fNrunsPerMaster<2) {
649 format = Form("%s.xml", fRunPrefix.Data());
650 AddDataFile(Form(format.Data(),irun));
653 if (((nruns-1)%fNrunsPerMaster) == 0) {
654 schunk = Form(fRunPrefix.Data(),irun);
656 format = Form("_%s.xml", fRunPrefix.Data());
657 schunk2 = Form(format.Data(), irun);
658 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
671 //______________________________________________________________________________
672 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
674 // Create dataset for the grid data directory + run number.
675 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
677 Error("CreateDataset", "Cannot create dataset with no grid connection");
682 if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
683 TString workdir = gGrid->GetHomeDirectory();
684 workdir += fGridWorkingDir;
686 // Compose the 'find' command arguments
689 TString options = "-x collection ";
690 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
691 TString conditions = "";
696 TString schunk, schunk2;
697 TGridCollection *cbase=0, *cadd=0;
698 if (!fRunNumbers.Length() && !fRunRange[0]) {
699 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
700 // Make a single data collection from data directory.
702 if (!DirectoryExists(path)) {
703 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
707 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
708 else file = Form("%s.xml", gSystem->BaseName(path));
709 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
715 command += conditions;
716 printf("command: %s\n", command.Data());
717 TGridResult *res = gGrid->Command(command);
719 // Write standard output to file
720 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
721 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
722 Bool_t nullFile = kFALSE;
724 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
726 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
728 Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
733 Bool_t fileExists = FileExists(file);
734 if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
735 // Copy xml file to alien space
736 if (fileExists) gGrid->Rm(file);
737 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
738 if (!FileExists(file)) {
739 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
742 // Update list of files to be processed.
744 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
748 Bool_t nullResult = kTRUE;
749 if (fRunNumbers.Length()) {
750 TObjArray *arr = fRunNumbers.Tokenize(" ");
753 while ((os=(TObjString*)next())) {
754 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
755 if (!DirectoryExists(path)) continue;
757 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
758 else file = Form("%s.xml", os->GetString().Data());
759 // If local collection file does not exist, create it via 'find' command.
760 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
765 command += conditions;
766 TGridResult *res = gGrid->Command(command);
768 // Write standard output to file
769 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
770 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
771 Bool_t nullFile = kFALSE;
773 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
775 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
777 Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
778 fRunNumbers.ReplaceAll(os->GetString().Data(), "");
784 if (TestBit(AliAnalysisGrid::kTest)) break;
785 // Check if there is one run per master job.
786 if (fNrunsPerMaster<2) {
787 if (FileExists(file)) {
788 if (fOverwriteMode) gGrid->Rm(file);
790 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
794 // Copy xml file to alien space
795 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
796 if (!FileExists(file)) {
797 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
803 if (((nruns-1)%fNrunsPerMaster) == 0) {
804 schunk = os->GetString();
805 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
807 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
808 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
812 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
815 schunk += Form("_%s.xml", os->GetString().Data());
816 if (FileExists(schunk)) {
817 if (fOverwriteMode) gGrid->Rm(file);
819 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
823 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
824 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
825 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
826 if (!FileExists(schunk)) {
827 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
835 Error("CreateDataset", "No valid dataset corresponding to the query!");
839 // Process a full run range.
840 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
841 format = Form("%%s/%s ", fRunPrefix.Data());
842 path = Form(format.Data(), fGridDataDir.Data(), irun);
843 if (!DirectoryExists(path)) continue;
845 format = Form("%s.xml", fRunPrefix.Data());
846 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
847 else file = Form(format.Data(), irun);
848 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
849 if (fOverwriteMode) gGrid->Rm(file);
851 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
855 // If local collection file does not exist, create it via 'find' command.
856 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
861 command += conditions;
862 TGridResult *res = gGrid->Command(command);
864 // Write standard output to file
865 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
866 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
867 Bool_t nullFile = kFALSE;
869 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
871 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
873 Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
879 if (TestBit(AliAnalysisGrid::kTest)) break;
880 // Check if there is one run per master job.
881 if (fNrunsPerMaster<2) {
882 if (FileExists(file)) {
883 if (fOverwriteMode) gGrid->Rm(file);
885 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
889 // Copy xml file to alien space
890 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
891 if (!FileExists(file)) {
892 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
897 // Check if the collection for the chunk exist locally.
898 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
899 if (FileExists(fInputFiles->At(nchunk)->GetName())) {
900 if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
903 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
904 if (((nruns-1)%fNrunsPerMaster) == 0) {
905 schunk = Form(fRunPrefix.Data(), irun);
906 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
908 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
912 format = Form("%%s_%s.xml", fRunPrefix.Data());
913 schunk2 = Form(format.Data(), schunk.Data(), irun);
914 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
918 if (FileExists(schunk)) {
919 if (fOverwriteMode) gGrid->Rm(schunk);
921 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
925 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
926 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
927 if (FileExists(schunk)) {
928 if (fOverwriteMode) gGrid->Rm(schunk);
930 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
934 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
935 if (!FileExists(schunk)) {
936 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
942 Error("CreateDataset", "No valid dataset corresponding to the query!");
949 //______________________________________________________________________________
950 Bool_t AliAnalysisAlien::CreateJDL()
952 // Generate a JDL file according to current settings. The name of the file is
953 // specified by fJDLName.
954 Bool_t error = kFALSE;
957 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
958 Bool_t generate = kTRUE;
959 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
961 Error("CreateJDL", "Alien connection required");
964 // Check validity of alien workspace
966 if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
967 if (!fProductionMode && !TestBit(AliAnalysisGrid::kTest)) CdWork();
968 workdir += fGridWorkingDir;
972 Error("CreateJDL()", "Define some input files for your analysis.");
975 // Compose list of input files
976 // Check if output files were defined
977 if (!fOutputFiles.Length()) {
978 Error("CreateJDL", "You must define at least one output file");
981 // Check if an output directory was defined and valid
982 if (!fGridOutputDir.Length()) {
983 Error("CreateJDL", "You must define AliEn output directory");
986 if (!fProductionMode) {
987 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
988 if (!DirectoryExists(fGridOutputDir)) {
989 if (gGrid->Mkdir(fGridOutputDir,"-p")) {
990 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
992 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
999 // Exit if any error up to now
1000 if (error) return kFALSE;
1002 if (!fUser.IsNull()) {
1003 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1004 fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1006 fGridJDL->SetExecutable(fExecutable, "This is the startup script");
1007 TString mergeExec = fExecutable;
1008 mergeExec.ReplaceAll(".sh", "_merge.sh");
1009 fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1010 mergeExec.ReplaceAll(".sh", ".C");
1011 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
1012 if (!fArguments.IsNull())
1013 fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1014 if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1015 else fMergingJDL->SetArguments("wn.xml $2 $3"); // xml, stage, laststage(0 or 1)
1017 fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1018 fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1019 fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1020 fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1022 if (fMaxInitFailed > 0) {
1023 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1024 fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1026 if (fSplitMaxInputFileNumber > 0) {
1027 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1028 fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1030 if (!IsOneStageMerging()) {
1031 fMergingJDL->SetValue("SplitMaxInputFileNumber", "\"$3\"");
1032 fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1034 if (fSplitMode.Length()) {
1035 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1036 fGridJDL->SetDescription("Split", "We split per SE or file");
1038 fMergingJDL->SetValue("Split", "\"se\"");
1039 fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1040 if (!fAliROOTVersion.IsNull()) {
1041 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1042 fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1044 if (!fROOTVersion.IsNull()) {
1045 fGridJDL->AddToPackages("ROOT", fROOTVersion);
1046 fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1048 if (!fAPIVersion.IsNull()) {
1049 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1050 fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1052 if (!fExternalPackages.IsNull()) {
1053 arr = fExternalPackages.Tokenize(" ");
1055 while ((os=(TObjString*)next())) {
1056 TString pkgname = os->GetString();
1057 Int_t index = pkgname.Index("::");
1058 TString pkgversion = pkgname(index+2, pkgname.Length());
1059 pkgname.Remove(index);
1060 fGridJDL->AddToPackages(pkgname, pkgversion);
1061 fMergingJDL->AddToPackages(pkgname, pkgversion);
1065 fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1066 fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1067 fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1068 fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1069 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1070 TString analysisFile = fExecutable;
1071 analysisFile.ReplaceAll(".sh", ".root");
1072 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1073 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1074 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
1075 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
1076 if (fAdditionalLibs.Length()) {
1077 arr = fAdditionalLibs.Tokenize(" ");
1079 while ((os=(TObjString*)next())) {
1080 if (os->GetString().Contains(".so")) continue;
1081 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1082 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1087 TIter next(fPackages);
1089 while ((obj=next())) {
1090 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1091 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1094 if (fOutputArchive.Length()) {
1095 arr = fOutputArchive.Tokenize(" ");
1097 Bool_t first = kTRUE;
1098 const char *comment = "Files to be archived";
1099 const char *comment1 = comment;
1100 while ((os=(TObjString*)next())) {
1101 if (!first) comment = NULL;
1102 if (!os->GetString().Contains("@") && fCloseSE.Length())
1103 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1105 fGridJDL->AddToOutputArchive(os->GetString(), comment);
1109 // Output archive for the merging jdl
1110 TString outputArchive;
1111 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1112 outputArchive = "log_archive.zip:std*,*.stat@disk=1 ";
1113 // Add normal output files, extra files + terminate files
1114 TString files = GetListOfFiles("outextter");
1115 // Do not register merge excludes
1116 if (!fMergeExcludes.IsNull()) {
1117 arr = fMergeExcludes.Tokenize(" ");
1119 while ((os=(TObjString*)next1())) {
1120 files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1121 files.ReplaceAll(os->GetString(),"");
1125 files.ReplaceAll(".root", "*.root");
1126 outputArchive += Form("root_archive.zip:%s@disk=%d",files.Data(),fNreplicas);
1128 TString files = fOutputArchive;
1129 files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1130 outputArchive = files;
1132 arr = outputArchive.Tokenize(" ");
1136 while ((os=(TObjString*)next2())) {
1137 if (!first) comment = NULL;
1138 TString currentfile = os->GetString();
1139 if (!currentfile.Contains("@") && fCloseSE.Length())
1140 fMergingJDL->AddToOutputArchive(Form("%s@%s",currentfile.Data(), fCloseSE.Data()), comment);
1142 fMergingJDL->AddToOutputArchive(currentfile, comment);
1147 arr = fOutputFiles.Tokenize(",");
1149 Bool_t first = kTRUE;
1150 const char *comment = "Files to be saved";
1151 while ((os=(TObjString*)next())) {
1152 // Ignore ouputs in jdl that are also in outputarchive
1153 TString sout = os->GetString();
1154 sout.ReplaceAll("*", "");
1155 sout.ReplaceAll(".root", "");
1156 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1157 if (fOutputArchive.Contains(sout)) continue;
1158 if (!first) comment = NULL;
1159 if (!os->GetString().Contains("@") && fCloseSE.Length())
1160 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1162 fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1164 if (fMergeExcludes.Contains(sout)) continue;
1165 if (!os->GetString().Contains("@") && fCloseSE.Length())
1166 fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1168 fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1171 fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1172 fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1173 TString validationScript = fValidationScript;
1174 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1175 validationScript.ReplaceAll(".sh", "_merge.sh");
1176 fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1177 if (fMasterResubmitThreshold) {
1178 fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1179 fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1181 // Write a jdl with 2 input parameters: collection name and output dir name.
1184 // Copy jdl to grid workspace
1186 // Check if an output directory was defined and valid
1187 if (!fGridOutputDir.Length()) {
1188 Error("CreateJDL", "You must define AliEn output directory");
1191 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1192 if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1193 if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1194 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
1196 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1202 if (TestBit(AliAnalysisGrid::kSubmit)) {
1203 TString mergeJDLName = fExecutable;
1204 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1205 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1206 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1207 if (fProductionMode) {
1208 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1209 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1211 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1212 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1213 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1214 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1216 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1217 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1220 if (fAdditionalLibs.Length()) {
1221 arr = fAdditionalLibs.Tokenize(" ");
1224 while ((os=(TObjString*)next())) {
1225 if (os->GetString().Contains(".so")) continue;
1226 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1227 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1228 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1233 TIter next(fPackages);
1235 while ((obj=next())) {
1236 if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1237 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
1238 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1245 //______________________________________________________________________________
1246 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1248 // Writes one or more JDL's corresponding to findex. If findex is negative,
1249 // all run numbers are considered in one go (jdl). For non-negative indices
1250 // they correspond to the indices in the array fInputFiles.
1251 if (!fInputFiles) return kFALSE;
1254 if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1255 workdir += fGridWorkingDir;
1256 fMergingJDL->AddToInputDataCollection("LF:$1/Stage_$2.xml,nodownload", "Collection of files to be merged for stage $2");
1257 fMergingJDL->SetOutputDirectory("$1/Stage_$2/#alien_counter_03i#", "Output directory");
1259 if (fProductionMode) {
1260 TIter next(fInputFiles);
1261 while ((os=next())) {
1262 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1264 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1266 if (!fRunNumbers.Length() && !fRunRange[0]) {
1267 // One jdl with no parameters in case input data is specified by name.
1268 TIter next(fInputFiles);
1270 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1271 if (!fOutputSingle.IsNull())
1272 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1274 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1275 fMergingJDL->SetOutputDirectory(fGridOutputDir);
1278 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1279 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1280 if (!fOutputSingle.IsNull()) {
1281 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1282 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1284 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1289 // Generate the JDL as a string
1290 TString sjdl = fGridJDL->Generate();
1291 TString sjdl1 = fMergingJDL->Generate();
1292 fMergingJDL->SetOutputDirectory("$1", "Output directory");
1293 fMergingJDL->AddToInputSandbox("LF:$1/$4");
1294 TString sjdl2 = fMergingJDL->Generate();
1295 Int_t index, index1;
1296 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1297 sjdl.ReplaceAll("(member", "\n (member");
1298 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1299 sjdl.ReplaceAll("{", "{\n ");
1300 sjdl.ReplaceAll("};", "\n};");
1301 sjdl.ReplaceAll("{\n \n", "{\n");
1302 sjdl.ReplaceAll("\n\n", "\n");
1303 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1304 sjdl1.ReplaceAll("\"LF:", "\n \"LF:");
1305 sjdl1.ReplaceAll("(member", "\n (member");
1306 sjdl1.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1307 sjdl1.ReplaceAll("{", "{\n ");
1308 sjdl1.ReplaceAll("};", "\n};");
1309 sjdl1.ReplaceAll("{\n \n", "{\n");
1310 sjdl1.ReplaceAll("\n\n", "\n");
1311 sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1312 sjdl2.ReplaceAll("\"LF:", "\n \"LF:");
1313 sjdl2.ReplaceAll("(member", "\n (member");
1314 sjdl2.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1315 sjdl2.ReplaceAll("{", "{\n ");
1316 sjdl2.ReplaceAll("};", "\n};");
1317 sjdl2.ReplaceAll("{\n \n", "{\n");
1318 sjdl2.ReplaceAll("\n\n", "\n");
1319 sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
1320 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1321 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
1322 index = sjdl.Index("JDLVariables");
1323 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1324 sjdl += "Workdirectorysize = {\"5000MB\"};";
1325 sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1326 sjdl1 += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1327 index = fJobTag.Index(":");
1328 if (index < 0) index = fJobTag.Length();
1329 TString jobTag = fJobTag;
1330 sjdl1.Prepend(Form("Jobtag = {\n \"comment:%s_Merging\"\n};\n", jobTag.Data()));
1331 sjdl1.Prepend("# Generated merging jdl \
1332 \n# $1 = full alien path to output directory to be merged \
1333 \n# $2 = merging stage \
1334 \n# $3 = maximum number of files to merge (must be >= 10000 for the last stage) \
1335 \n# $4 = xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1336 sjdl2.Prepend(Form("Jobtag = {\n \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
1337 sjdl2.Prepend("# Generated merging jdl \
1338 \n# $1 = full alien path to output directory to be merged \
1339 \n# $2 = merging stage \
1340 \n# $3 = maximum number of files to merge (must be >= 10000 for the last stage) \
1341 \n# $4 = xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1342 index = sjdl1.Index("JDLVariables");
1343 if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1344 index = sjdl2.Index("JDLVariables");
1345 if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
1346 sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1347 sjdl2 += "Workdirectorysize = {\"5000MB\"};";
1348 index = sjdl2.Index("Split =");
1350 index1 = sjdl2.Index("\n", index);
1351 sjdl2.Remove(index, index1-index+1);
1353 index = sjdl2.Index("SplitMaxInputFileNumber");
1355 index1 = sjdl2.Index("\n", index);
1356 sjdl2.Remove(index, index1-index+1);
1358 index = sjdl2.Index("InputDataCollection");
1360 index1 = sjdl2.Index(";", index);
1361 sjdl2.Remove(index, index1-index+1);
1363 index = sjdl2.Index("InputDataListFormat");
1365 index1 = sjdl2.Index("\n", index);
1366 sjdl2.Remove(index, index1-index+1);
1368 index = sjdl2.Index("InputDataList");
1370 index1 = sjdl2.Index("\n", index);
1371 sjdl2.Remove(index, index1-index+1);
1373 sjdl2.ReplaceAll("wn.xml", "$4");
1374 // Write jdl to file
1376 out.open(fJDLName.Data(), ios::out);
1378 Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
1381 out << sjdl << endl;
1383 TString mergeJDLName = fExecutable;
1384 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1387 out1.open(mergeJDLName.Data(), ios::out);
1389 Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
1392 out1 << sjdl1 << endl;
1395 TString finalJDL = mergeJDLName;
1396 finalJDL.ReplaceAll(".jdl", "_final.jdl");
1397 out2.open(finalJDL.Data(), ios::out);
1399 Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
1402 out2 << sjdl2 << endl;
1406 // Copy jdl to grid workspace
1408 Info("WriteJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1410 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1411 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1412 TString finalJDL = mergeJDLName;
1413 finalJDL.ReplaceAll(".jdl", "_final.jdl");
1414 TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
1415 if (fProductionMode) {
1416 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1417 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1418 locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
1420 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1421 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1422 if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
1423 Info("WriteJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1424 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1426 Info("WriteJDL", "\n##### Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
1427 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1428 TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
1434 //______________________________________________________________________________
1435 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1437 // Returns true if file exists.
1438 if (!gGrid) return kFALSE;
1440 slfn.ReplaceAll("alien://","");
1441 TGridResult *res = gGrid->Ls(slfn);
1442 if (!res) return kFALSE;
1443 TMap *map = dynamic_cast<TMap*>(res->At(0));
1448 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1449 if (!objs || !objs->GetString().Length()) {
1457 //______________________________________________________________________________
1458 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1460 // Returns true if directory exists. Can be also a path.
1461 if (!gGrid) return kFALSE;
1462 // Check if dirname is a path
1463 TString dirstripped = dirname;
1464 dirstripped = dirstripped.Strip();
1465 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1466 TString dir = gSystem->BaseName(dirstripped);
1468 TString path = gSystem->DirName(dirstripped);
1469 TGridResult *res = gGrid->Ls(path, "-F");
1470 if (!res) return kFALSE;
1474 while ((map=dynamic_cast<TMap*>(next()))) {
1475 obj = map->GetValue("name");
1477 if (dir == obj->GetName()) {
1486 //______________________________________________________________________________
1487 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
1489 // Check input data type.
1490 isCollection = kFALSE;
1494 Error("CheckDataType", "No connection to grid");
1497 isCollection = IsCollection(lfn);
1498 TString msg = "\n##### file: ";
1501 msg += " type: raw_collection;";
1502 // special treatment for collections
1504 // check for tag files in the collection
1505 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1507 msg += " using_tags: No (unknown)";
1508 Info("CheckDataType", "%s", msg.Data());
1511 const char* typeStr = res->GetKey(0, "origLFN");
1512 if (!typeStr || !strlen(typeStr)) {
1513 msg += " using_tags: No (unknown)";
1514 Info("CheckDataType", "%s", msg.Data());
1517 TString file = typeStr;
1518 useTags = file.Contains(".tag");
1519 if (useTags) msg += " using_tags: Yes";
1520 else msg += " using_tags: No";
1521 Info("CheckDataType", "%s", msg.Data());
1526 isXml = slfn.Contains(".xml");
1528 // Open xml collection and check if there are tag files inside
1529 msg += " type: xml_collection;";
1530 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1532 msg += " using_tags: No (unknown)";
1533 Info("CheckDataType", "%s", msg.Data());
1536 TMap *map = coll->Next();
1538 msg += " using_tags: No (unknown)";
1539 Info("CheckDataType", "%s", msg.Data());
1542 map = (TMap*)map->GetValue("");
1544 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1545 useTags = file.Contains(".tag");
1547 if (useTags) msg += " using_tags: Yes";
1548 else msg += " using_tags: No";
1549 Info("CheckDataType", "%s", msg.Data());
1552 useTags = slfn.Contains(".tag");
1553 if (slfn.Contains(".root")) msg += " type: root file;";
1554 else msg += " type: unknown file;";
1555 if (useTags) msg += " using_tags: Yes";
1556 else msg += " using_tags: No";
1557 Info("CheckDataType", "%s", msg.Data());
1560 //______________________________________________________________________________
1561 void AliAnalysisAlien::EnablePackage(const char *package)
1563 // Enables a par file supposed to exist in the current directory.
1564 TString pkg(package);
1565 pkg.ReplaceAll(".par", "");
1567 if (gSystem->AccessPathName(pkg)) {
1568 Fatal("EnablePackage", "Package %s not found", pkg.Data());
1571 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1572 Info("EnablePackage", "AliEn plugin will use .par packages");
1573 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1575 fPackages = new TObjArray();
1576 fPackages->SetOwner();
1578 fPackages->Add(new TObjString(pkg));
1581 //______________________________________________________________________________
1582 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
1584 // Make a tree from files having the location specified in fFileForTestMode.
1585 // Inspired from JF's CreateESDChain.
1586 if (fFileForTestMode.IsNull()) {
1587 Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
1590 if (gSystem->AccessPathName(fFileForTestMode)) {
1591 Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
1596 in.open(fFileForTestMode);
1598 // Read the input list of files and add them to the chain
1600 TChain *chain = new TChain(treeName);
1604 if (line.IsNull()) continue;
1605 if (count++ == fNtestFiles) break;
1606 TString esdFile(line);
1607 TFile *file = TFile::Open(esdFile);
1609 if (!file->IsZombie()) chain->Add(esdFile);
1612 Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
1616 if (!chain->GetListOfFiles()->GetEntries()) {
1617 Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
1625 //______________________________________________________________________________
1626 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1628 // Get job status for all jobs with jobid>jobidstart.
1629 static char mstatus[20];
1635 TGridJobStatusList *list = gGrid->Ps("");
1636 if (!list) return mstatus;
1637 Int_t nentries = list->GetSize();
1638 TGridJobStatus *status;
1640 for (Int_t ijob=0; ijob<nentries; ijob++) {
1641 status = (TGridJobStatus *)list->At(ijob);
1642 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1643 if (pid<jobidstart) continue;
1644 if (pid == lastid) {
1645 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1647 switch (status->GetStatus()) {
1648 case TGridJobStatus::kWAITING:
1650 case TGridJobStatus::kRUNNING:
1652 case TGridJobStatus::kABORTED:
1653 case TGridJobStatus::kFAIL:
1654 case TGridJobStatus::kUNKNOWN:
1656 case TGridJobStatus::kDONE:
1665 //______________________________________________________________________________
1666 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1668 // Returns true if file is a collection. Functionality duplicated from
1669 // TAlien::Type() because we don't want to directly depend on TAlien.
1671 Error("IsCollection", "No connection to grid");
1674 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1675 if (!res) return kFALSE;
1676 const char* typeStr = res->GetKey(0, "type");
1677 if (!typeStr || !strlen(typeStr)) return kFALSE;
1678 if (!strcmp(typeStr, "collection")) return kTRUE;
1683 //______________________________________________________________________________
1684 Bool_t AliAnalysisAlien::IsSingleOutput() const
1686 // Check if single-ouput option is on.
1687 return (!fOutputSingle.IsNull());
1690 //______________________________________________________________________________
1691 void AliAnalysisAlien::Print(Option_t *) const
1693 // Print current plugin settings.
1694 printf("### AliEn analysis plugin current settings ###\n");
1695 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1696 if (mgr && mgr->IsProofMode()) {
1697 TString proofType = "= PLUGIN IN PROOF MODE ON CLUSTER:_________________";
1698 if (TestBit(AliAnalysisGrid::kTest))
1699 proofType = "= PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
1700 printf("%s %s\n", proofType.Data(), fProofCluster.Data());
1701 if (!fProofDataSet.IsNull())
1702 printf("= Requested data set:___________________________ %s\n", fProofDataSet.Data());
1704 printf("= Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");
1706 printf("= Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");
1707 if (!fRootVersionForProof.IsNull())
1708 printf("= ROOT version requested________________________ %s\n", fRootVersionForProof.Data());
1710 printf("= ROOT version requested________________________ default\n");
1711 printf("= AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
1712 if (!fAliRootMode.IsNull())
1713 printf("= Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());
1715 printf("= Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
1716 if (fNproofWorkersPerSlave)
1717 printf("= Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
1718 if (TestSpecialBit(kClearPackages))
1719 printf("= ClearPackages requested...\n");
1720 if (fIncludePath.Data())
1721 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1722 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1723 if (fPackages && fPackages->GetEntries()) {
1724 TIter next(fPackages);
1727 while ((obj=next())) list += obj->GetName();
1728 printf("= Par files to be used: ________________________ %s\n", list.Data());
1730 if (TestSpecialBit(kProofConnectGrid))
1731 printf("= Requested PROOF connection to grid\n");
1734 printf("= OverwriteMode:________________________________ %d\n", fOverwriteMode);
1735 if (fOverwriteMode) {
1736 printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
1737 \n***** To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
1739 printf("= Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
1740 printf("= Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
1741 printf("= Production mode:______________________________ %d\n", fProductionMode);
1742 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1743 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1744 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1746 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1747 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1748 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1749 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1750 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1751 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1752 if (fRunNumbers.Length())
1753 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1755 printf("= Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
1756 if (!fRunRange[0] && !fRunNumbers.Length()) {
1757 TIter next(fInputFiles);
1760 while ((obj=next())) list += obj->GetName();
1761 printf("= Input files to be processed: _________________ %s\n", list.Data());
1763 if (TestBit(AliAnalysisGrid::kTest))
1764 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1765 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1766 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1767 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1768 printf("= List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
1769 printf("=====================================================================\n");
1770 printf("= Job price: ___________________________________ %d\n", fPrice);
1771 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1772 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1773 if (fMaxInitFailed>0)
1774 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1775 if (fMasterResubmitThreshold>0)
1776 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1777 printf("= Number of replicas for the output files_______ %d\n", fNreplicas);
1778 if (fNrunsPerMaster>0)
1779 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1780 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1781 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1782 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
1783 if (fArguments.Length())
1784 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1785 if (fExecutableArgs.Length())
1786 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1787 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1788 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1789 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1790 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1792 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1793 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1794 if (fIncludePath.Data())
1795 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1796 if (fCloseSE.Length())
1797 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1798 if (fFriendChainName.Length())
1799 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1800 if (fPackages && fPackages->GetEntries()) {
1801 TIter next(fPackages);
1804 while ((obj=next())) list += obj->GetName();
1805 printf("= Par files to be used: ________________________ %s\n", list.Data());
1809 //______________________________________________________________________________
1810 void AliAnalysisAlien::SetDefaults()
1812 // Set default values for everything. What cannot be filled will be left empty.
1813 if (fGridJDL) delete fGridJDL;
1814 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1815 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1818 fSplitMaxInputFileNumber = 100;
1820 fMasterResubmitThreshold = 0;
1825 fNrunsPerMaster = 1;
1826 fMaxMergeFiles = 100;
1828 fExecutable = "analysis.sh";
1829 fExecutableCommand = "root -b -q";
1831 fExecutableArgs = "";
1832 fAnalysisMacro = "myAnalysis.C";
1833 fAnalysisSource = "";
1834 fAdditionalLibs = "";
1838 fAliROOTVersion = "";
1839 fUser = ""; // Your alien user name
1840 fGridWorkingDir = "";
1841 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1842 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1843 fFriendChainName = "";
1844 fGridOutputDir = "output";
1845 fOutputArchive = "log_archive.zip:std*,*.stat@disk=1 root_archive.zip:*.root@disk=2";
1846 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1847 fInputFormat = "xml-single";
1848 fJDLName = "analysis.jdl";
1849 fJobTag = "Automatically generated analysis JDL";
1850 fMergeExcludes = "";
1853 SetCheckCopy(kTRUE);
1854 SetDefaultOutputs(kTRUE);
1858 //______________________________________________________________________________
1859 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
1861 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
1862 // First check if the result is already in the output directory.
1863 if (FileExists(Form("%s/%s",aliendir,filename))) {
1864 printf("Final merged results found. Not merging again.\n");
1867 // Now check the last stage done.
1870 if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
1873 // Next stage of merging
1875 TString pattern = "*root_archive.zip";
1876 if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
1877 TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
1878 if (res) delete res;
1879 // Write standard output to file
1880 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
1881 // Count the number of files inside
1883 ifile.open(Form("Stage_%d.xml",stage));
1884 if (!ifile.good()) {
1885 ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
1890 while (!ifile.eof()) {
1892 if (line.Contains("/event")) nfiles++;
1896 ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
1899 printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
1901 // Copy the file in the output directory
1902 printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
1903 TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
1904 // Check if this is the last stage to be done.
1905 Bool_t laststage = (nfiles<nperchunk);
1906 if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
1908 printf("### Submiting final merging stage %d\n", stage);
1909 TString finalJDL = jdl;
1910 finalJDL.ReplaceAll(".jdl", "_final.jdl");
1911 TString query = Form("submit %s %s %d 10000 Stage_%d.xml", finalJDL.Data(), aliendir, stage, stage);
1912 Int_t jobId = SubmitSingleJob(query);
1913 if (!jobId) return kFALSE;
1915 printf("### Submiting merging stage %d\n", stage);
1916 TString query = Form("submit %s %s %d %d wn.xml", jdl, aliendir, stage, nperchunk);
1917 Int_t jobId = SubmitSingleJob(query);
1918 if (!jobId) return kFALSE;
1923 //______________________________________________________________________________
1924 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
1926 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
1927 if (!gGrid) return 0;
1928 printf("=> %s ------> ",query);
1929 TGridResult *res = gGrid->Command(query);
1931 TString jobId = res->GetKey(0,"jobId");
1933 if (jobId.IsNull()) {
1934 printf("submission failed. Reason:\n");
1937 ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
1940 printf(" Job id: %s\n", jobId.Data());
1944 //______________________________________________________________________________
1945 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
1947 // Merge given output files from basedir. Basedir can be an alien output directory
1948 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
1949 // files in a group (ignored for xml input). Merging can be done in stages:
1950 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
1951 // stage=1 : works with an xml of all root_archive.zip in the output directory
1952 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
1953 TString outputFile = output;
1955 TString outputChunk;
1956 TString previousChunk = "";
1957 TObjArray *listoffiles = new TObjArray();
1958 // listoffiles->SetOwner();
1959 Int_t countChunk = 0;
1960 Int_t countZero = nmaxmerge;
1961 Bool_t merged = kTRUE;
1962 Int_t index = outputFile.Index("@");
1963 if (index > 0) outputFile.Remove(index);
1964 TString inputFile = outputFile;
1965 TString sbasedir = basedir;
1966 if (sbasedir.Contains(".xml")) {
1967 // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
1968 nmaxmerge = 9999999;
1969 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
1971 ::Error("MergeOutput", "Input XML collection empty.");
1974 // Iterate grid collection
1975 while (coll->Next()) {
1976 TString fname = gSystem->DirName(coll->GetTURL());
1979 listoffiles->Add(new TNamed(fname.Data(),""));
1982 command = Form("find %s/ *%s", basedir, inputFile.Data());
1983 printf("command: %s\n", command.Data());
1984 TGridResult *res = gGrid->Command(command);
1986 ::Error("MergeOutput","No result for the find command\n");
1992 while ((map=(TMap*)nextmap())) {
1993 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1994 if (!objs || !objs->GetString().Length()) {
1995 // Nothing found - skip this output
2000 listoffiles->Add(new TNamed(objs->GetName(),""));
2004 if (!listoffiles->GetEntries()) {
2005 ::Error("MergeOutput","No result for the find command\n");
2010 TFileMerger *fm = 0;
2011 TIter next0(listoffiles);
2012 TObjArray *listoffilestmp = new TObjArray();
2013 listoffilestmp->SetOwner();
2016 // Keep only the files at upper level
2017 Int_t countChar = 0;
2018 while ((nextfile=next0())) {
2019 snextfile = nextfile->GetName();
2020 Int_t crtCount = snextfile.CountChar('/');
2021 if (nextfile == listoffiles->First()) countChar = crtCount;
2022 if (crtCount < countChar) countChar = crtCount;
2025 while ((nextfile=next0())) {
2026 snextfile = nextfile->GetName();
2027 Int_t crtCount = snextfile.CountChar('/');
2028 if (crtCount > countChar) {
2032 listoffilestmp->Add(nextfile);
2035 listoffiles = listoffilestmp; // Now contains 'good' files
2036 listoffiles->Print();
2037 TIter next(listoffiles);
2038 // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2039 outputChunk = outputFile;
2040 outputChunk.ReplaceAll(".root", "_*.root");
2041 // Check for existent temporary merge files
2042 // Check overwrite mode and remove previous partial results if needed
2043 // Preserve old merging functionality for stage 0.
2045 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2047 // Skip as many input files as in a chunk
2048 for (Int_t counter=0; counter<nmaxmerge; counter++) {
2051 ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
2055 snextfile = nextfile->GetName();
2057 outputChunk = outputFile;
2058 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2060 if (gSystem->AccessPathName(outputChunk)) continue;
2061 // Merged file with chunks up to <countChunk> found
2062 ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
2063 previousChunk = outputChunk;
2067 countZero = nmaxmerge;
2069 while ((nextfile=next())) {
2070 snextfile = nextfile->GetName();
2071 // Loop 'find' results and get next LFN
2072 if (countZero == nmaxmerge) {
2073 // First file in chunk - create file merger and add previous chunk if any.
2074 fm = new TFileMerger(kFALSE);
2075 fm->SetFastMethod(kTRUE);
2076 if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
2077 outputChunk = outputFile;
2078 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2080 // If last file found, put merged results in the output file
2081 if (nextfile == listoffiles->Last()) outputChunk = outputFile;
2082 // Add file to be merged and decrement chunk counter.
2083 fm->AddFile(snextfile);
2085 if (countZero==0 || nextfile == listoffiles->Last()) {
2086 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2087 // Nothing found - skip this output
2088 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2092 fm->OutputFile(outputChunk);
2093 // Merge the outputs, then go to next chunk
2095 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2099 ::Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
2100 gSystem->Unlink(previousChunk);
2102 if (nextfile == listoffiles->Last()) break;
2104 countZero = nmaxmerge;
2105 previousChunk = outputChunk;
2112 // Merging stage different than 0.
2113 // Move to the begining of the requested chunk.
2114 fm = new TFileMerger(kFALSE);
2115 fm->SetFastMethod(kTRUE);
2116 while ((nextfile=next())) fm->AddFile(nextfile->GetName());
2118 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2119 // Nothing found - skip this output
2120 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2124 fm->OutputFile(outputFile);
2125 // Merge the outputs
2127 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2131 ::Info("MergeOutput", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
2137 //______________________________________________________________________________
2138 Bool_t AliAnalysisAlien::MergeOutputs()
2140 // Merge analysis outputs existing in the AliEn space.
2141 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
2142 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2144 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
2148 if (!TestBit(AliAnalysisGrid::kMerge)) {
2149 Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
2152 if (fProductionMode) {
2153 Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
2156 Info("MergeOutputs", "Submitting merging JDL");
2157 if (!SubmitMerging()) return kFALSE;
2158 Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
2159 Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
2162 // Get the output path
2163 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2164 if (!DirectoryExists(fGridOutputDir)) {
2165 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
2168 if (!fOutputFiles.Length()) {
2169 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2172 // Check if fast read option was requested
2173 Info("MergeOutputs", "Started local merging of output files from: alien://%s \
2174 \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
2175 if (fFastReadOption) {
2176 Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
2177 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2178 gEnv->SetValue("XNet.ConnectTimeout",50);
2179 gEnv->SetValue("XNet.RequestTimeout",50);
2180 gEnv->SetValue("XNet.MaxRedirectCount",2);
2181 gEnv->SetValue("XNet.ReconnectTimeout",50);
2182 gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
2184 // Make sure we change the temporary directory
2185 gSystem->Setenv("TMPDIR", gSystem->pwd());
2186 TObjArray *list = fOutputFiles.Tokenize(",");
2190 Bool_t merged = kTRUE;
2191 while((str=(TObjString*)next())) {
2192 outputFile = str->GetString();
2193 Int_t index = outputFile.Index("@");
2194 if (index > 0) outputFile.Remove(index);
2195 TString outputChunk = outputFile;
2196 outputChunk.ReplaceAll(".root", "_*.root");
2197 // Skip already merged outputs
2198 if (!gSystem->AccessPathName(outputFile)) {
2199 if (fOverwriteMode) {
2200 Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
2201 gSystem->Unlink(outputFile);
2202 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2203 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2204 outputChunk.Data());
2205 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2208 Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
2212 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2213 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2214 outputChunk.Data());
2215 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2218 if (fMergeExcludes.Length() &&
2219 fMergeExcludes.Contains(outputFile.Data())) continue;
2220 // Perform a 'find' command in the output directory, looking for registered outputs
2221 merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
2223 Error("MergeOutputs", "Terminate() will NOT be executed");
2226 TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2227 if (fileOpened) fileOpened->Close();
2232 //______________________________________________________________________________
2233 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2235 // Use the output files connected to output containers from the analysis manager
2236 // rather than the files defined by SetOutputFiles
2237 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
2238 Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
2239 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2242 //______________________________________________________________________________
2243 void AliAnalysisAlien::SetOutputFiles(const char *list)
2245 // Manually set the output files list.
2246 // Removes duplicates. Not allowed if default outputs are not disabled.
2247 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2248 Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2251 Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2253 TString slist = list;
2254 if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2255 TObjArray *arr = slist.Tokenize(" ");
2259 while ((os=(TObjString*)next())) {
2260 sout = os->GetString();
2261 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2262 if (fOutputFiles.Contains(sout)) continue;
2263 if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2264 fOutputFiles += sout;
2269 //______________________________________________________________________________
2270 void AliAnalysisAlien::SetOutputArchive(const char *list)
2272 // Manually set the output archive list. Free text - you are on your own...
2273 // Not allowed if default outputs are not disabled.
2274 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2275 Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2278 Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2279 fOutputArchive = list;
2282 //______________________________________________________________________________
2283 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2285 // Setting a prefered output SE is not allowed anymore.
2286 Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2289 //______________________________________________________________________________
2290 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
2292 // Start remote grid analysis.
2293 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2294 Bool_t testMode = TestBit(AliAnalysisGrid::kTest);
2295 if (!mgr || !mgr->IsInitialized()) {
2296 Error("StartAnalysis", "You need an initialized analysis manager for this");
2299 // Are we in PROOF mode ?
2300 if (mgr->IsProofMode()) {
2301 Info("StartAnalysis", "##### Starting PROOF analysis on cluster <%s> via the plugin #####", fProofCluster.Data());
2302 if (fProofCluster.IsNull()) {
2303 Error("StartAnalysis", "You need to specify the proof cluster name via SetProofCluster");
2306 if (fProofDataSet.IsNull() && !testMode) {
2307 Error("StartAnalysis", "You need to specify a dataset using SetProofDataSet()");
2310 // Set the needed environment
2311 gEnv->SetValue("XSec.GSI.DelegProxy","2");
2312 // Do we need to reset PROOF ? The success of the Reset operation cannot be checked
2313 if (fProofReset && !testMode) {
2314 if (fProofReset==1) {
2315 Info("StartAnalysis", "Sending soft reset signal to proof cluster %s", fProofCluster.Data());
2316 gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kFALSE);", fProofCluster.Data()));
2318 Info("StartAnalysis", "Sending hard reset signal to proof cluster %s", fProofCluster.Data());
2319 gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kTRUE);", fProofCluster.Data()));
2321 Info("StartAnalysis", "Stopping the analysis. Please use SetProofReset(0) to resume.");
2324 // Do we need to change the ROOT version ? The success of this cannot be checked.
2325 if (!fRootVersionForProof.IsNull() && !testMode) {
2326 gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"%s\");",
2327 fProofCluster.Data(), fRootVersionForProof.Data()));
2329 // Connect to PROOF and check the status
2332 if (fNproofWorkersPerSlave) sworkers = Form("workers=%dx", fNproofWorkersPerSlave);
2333 else if (fNproofWorkers) sworkers = Form("workers=%d", fNproofWorkers);
2335 if (!sworkers.IsNull())
2336 proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"%s\");", fProofCluster.Data(), sworkers.Data()));
2338 proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
2340 proof = gROOT->ProcessLine("TProof::Open(\"\");");
2342 Error("StartAnalysis", "Could not start PROOF in test mode");
2347 Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
2350 if (fNproofWorkersPerSlave*fNproofWorkers > 0)
2351 gROOT->ProcessLine(Form("gProof->SetParallel(%d);", fNproofWorkers));
2352 // Is dataset existing ?
2354 TString dataset = fProofDataSet;
2355 Int_t index = dataset.Index("#");
2356 if (index>=0) dataset.Remove(index);
2357 // if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
2358 // Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
2361 // Info("StartAnalysis", "Dataset %s found", dataset.Data());
2363 // Is ClearPackages() needed ?
2364 if (TestSpecialBit(kClearPackages)) {
2365 Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
2366 gROOT->ProcessLine("gProof->ClearPackages();");
2368 // Is a given aliroot mode requested ?
2371 if (!fAliRootMode.IsNull()) {
2372 TString alirootMode = fAliRootMode;
2373 if (alirootMode == "default") alirootMode = "";
2374 Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
2375 optionsList.SetOwner();
2376 optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
2377 // Check the additional libs to be loaded
2379 Bool_t parMode = kFALSE;
2380 if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:ANALYSISalice";
2381 // Parse the extra libs for .so
2382 if (fAdditionalLibs.Length()) {
2383 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2386 while((str=(TObjString*)next())) {
2387 if (str->GetString().Contains(".so")) {
2389 Warning("StartAnalysis", "Plugin does not support loading libs after par files in PROOF mode. Library %s and following will not load on workers", str->GetName());
2392 TString stmp = str->GetName();
2393 if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
2394 stmp.ReplaceAll(".so","");
2395 if (!extraLibs.IsNull()) extraLibs += ":";
2399 if (str->GetString().Contains(".par")) {
2400 // The first par file found in the list will not allow any further .so
2402 if (!parLibs.IsNull()) parLibs += ":";
2403 parLibs += str->GetName();
2407 if (list) delete list;
2409 if (!extraLibs.IsNull()) optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
2410 // Check extra includes
2411 if (!fIncludePath.IsNull()) {
2412 TString includePath = fIncludePath;
2413 includePath.ReplaceAll(" ",":");
2414 includePath.Strip(TString::kTrailing, ':');
2415 Info("StartAnalysis", "Adding extra includes: %s",includePath.Data());
2416 optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
2418 // Check if connection to grid is requested
2419 if (TestSpecialBit(kProofConnectGrid))
2420 optionsList.Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
2421 // Enable AliRoot par
2423 // Enable proof lite package
2424 TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
2425 for (Int_t i=0; i<optionsList.GetSize(); i++) {
2426 TNamed *obj = (TNamed*)optionsList.At(i);
2427 printf("%s %s\n", obj->GetName(), obj->GetTitle());
2429 if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
2430 && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)0x%lx);",alirootLite.Data(),(ULong_t)&optionsList))) {
2431 Info("StartAnalysis", "AliRootProofLite enabled");
2433 Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
2437 if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)0x%lx);",
2438 fAliROOTVersion.Data(), (ULong_t)&optionsList))) {
2439 Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
2443 // Enable first par files from fAdditionalLibs
2444 if (!parLibs.IsNull()) {
2445 TObjArray *list = parLibs.Tokenize(":");
2447 TObjString *package;
2448 while((package=(TObjString*)next())) {
2449 TString spkg = package->GetName();
2450 spkg.ReplaceAll(".par", "");
2451 gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2452 if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2453 TString enablePackage = (testMode)?Form("gProof->EnablePackage(\"%s\",kFALSE);", package->GetName()):Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName());
2454 if (gROOT->ProcessLine(enablePackage)) {
2455 Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2459 Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2463 if (list) delete list;
2466 if (fAdditionalLibs.Contains(".so") && !testMode) {
2467 Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
2468 \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
2472 // Enable par files if requested
2473 if (fPackages && fPackages->GetEntries()) {
2474 TIter next(fPackages);
2476 while ((package=next())) {
2477 // Skip packages already enabled
2478 if (parLibs.Contains(package->GetName())) continue;
2479 TString spkg = package->GetName();
2480 spkg.ReplaceAll(".par", "");
2481 gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2482 if (gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2483 if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName()))) {
2484 Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2488 Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2493 // Do we need to load analysis source files ?
2494 // NOTE: don't load on client since this is anyway done by the user to attach his task.
2495 if (fAnalysisSource.Length()) {
2496 TObjArray *list = fAnalysisSource.Tokenize(" ");
2499 while((str=(TObjString*)next())) {
2500 gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
2502 if (list) delete list;
2505 // Register dataset to proof lite.
2506 if (fFileForTestMode.IsNull()) {
2507 Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2510 if (gSystem->AccessPathName(fFileForTestMode)) {
2511 Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2514 TFileCollection *coll = new TFileCollection();
2515 coll->AddFromFile(fFileForTestMode);
2516 gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)0x%lx, \"OV\");", (ULong_t)coll));
2517 gROOT->ProcessLine("gProof->ShowDataSets()");
2522 // Check if output files have to be taken from the analysis manager
2523 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2524 // Add output files and AOD files
2525 fOutputFiles = GetListOfFiles("outaod");
2526 // Add extra files registered to the analysis manager
2527 TString extra = GetListOfFiles("ext");
2528 if (!extra.IsNull()) {
2529 extra.ReplaceAll(".root", "*.root");
2530 if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2531 fOutputFiles += extra;
2533 // Compose the output archive.
2534 fOutputArchive = "log_archive.zip:std*,*.stat@disk=1 ";
2535 fOutputArchive += Form("root_archive.zip:%s@disk=%d",fOutputFiles.Data(),fNreplicas);
2537 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
2538 if (TestBit(AliAnalysisGrid::kOffline)) {
2539 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2540 \n there nor any job run. You can revise the JDL and analysis \
2541 \n macro then run the same in \"submit\" mode.");
2542 } else if (TestBit(AliAnalysisGrid::kTest)) {
2543 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
2545 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2546 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
2547 \n space and job submitted.");
2548 } else if (TestBit(AliAnalysisGrid::kMerge)) {
2549 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
2550 if (fMergeViaJDL) CheckInputData();
2553 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
2558 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
2561 if (IsCheckCopy() && gGrid) CheckFileCopy(gGrid->GetHomeDirectory());
2562 if (!CheckInputData()) {
2563 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
2566 if (!CreateDataset(fDataPattern)) {
2568 if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2569 if (fRunNumbers.Length()) serror = "run numbers";
2570 if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2571 serror += Form("\n or data pattern <%s>", fDataPattern.Data());
2572 Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2575 WriteAnalysisFile();
2576 WriteAnalysisMacro();
2578 WriteValidationScript();
2580 WriteMergingMacro();
2581 WriteMergeExecutable();
2582 WriteValidationScript(kTRUE);
2584 if (!CreateJDL()) return kFALSE;
2585 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2587 // Locally testing the analysis
2588 Info("StartAnalysis", "\n_______________________________________________________________________ \
2589 \n Running analysis script in a daughter shell as on a worker node \
2590 \n_______________________________________________________________________");
2591 TObjArray *list = fOutputFiles.Tokenize(",");
2595 while((str=(TObjString*)next())) {
2596 outputFile = str->GetString();
2597 Int_t index = outputFile.Index("@");
2598 if (index > 0) outputFile.Remove(index);
2599 if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
2602 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
2603 gSystem->Exec(Form("bash %s",fValidationScript.Data()));
2604 // gSystem->Exec("cat stdout");
2607 // Check if submitting is managed by LPM manager
2608 if (fProductionMode) {
2609 TString prodfile = fJDLName;
2610 prodfile.ReplaceAll(".jdl", ".prod");
2611 WriteProductionFile(prodfile);
2612 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2615 // Submit AliEn job(s)
2616 gGrid->Cd(fGridOutputDir);
2619 if (!fRunNumbers.Length() && !fRunRange[0]) {
2620 // Submit a given xml or a set of runs
2621 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
2622 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
2624 const char *cjobId = res->GetKey(0,"jobId");
2628 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
2631 Info("StartAnalysis", "\n_______________________________________________________________________ \
2632 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2633 \n_______________________________________________________________________",
2634 fJDLName.Data(), cjobId);
2639 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2643 // Submit for a range of enumeration of runs.
2644 if (!Submit()) return kFALSE;
2647 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2648 \n You may exit at any time and terminate the job later using the option <terminate> \
2649 \n ##################################################################################", jobID.Data());
2650 gSystem->Exec("aliensh");
2654 //______________________________________________________________________________
2655 const char *AliAnalysisAlien::GetListOfFiles(const char *type)
2657 // Get a comma-separated list of output files of the requested type.
2658 // Type can be (case unsensitive):
2659 // aod - list of aod files (std, extensions and filters)
2660 // out - list of output files connected to containers (but not aod's or extras)
2661 // ext - list of extra files registered to the manager
2662 // ter - list of files produced in terminate
2663 static TString files;
2665 TString stype = type;
2667 TString aodfiles, extra;
2668 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2670 ::Error("GetListOfFiles", "Cannot call this without analysis manager");
2671 return files.Data();
2673 if (mgr->GetOutputEventHandler()) {
2674 aodfiles = mgr->GetOutputEventHandler()->GetOutputFileName();
2675 TString extraaod = mgr->GetOutputEventHandler()->GetExtraOutputs();
2676 if (!extraaod.IsNull()) {
2678 aodfiles += extraaod;
2681 if (stype.Contains("aod")) {
2683 if (stype == "aod") return files.Data();
2685 // Add output files that are not in the list of AOD files
2686 TString outputfiles = "";
2687 TIter next(mgr->GetOutputs());
2688 AliAnalysisDataContainer *output;
2689 const char *filename = 0;
2690 while ((output=(AliAnalysisDataContainer*)next())) {
2691 filename = output->GetFileName();
2692 if (!(strcmp(filename, "default"))) continue;
2693 if (outputfiles.Contains(filename)) continue;
2694 if (aodfiles.Contains(filename)) continue;
2695 if (!outputfiles.IsNull()) outputfiles += ",";
2696 outputfiles += filename;
2698 if (stype.Contains("out")) {
2699 if (!files.IsNull()) files += ",";
2700 files += outputfiles;
2701 if (stype == "out") return files.Data();
2703 // Add extra files registered to the analysis manager
2705 extra = mgr->GetExtraFiles();
2706 if (!extra.IsNull()) {
2708 extra.ReplaceAll(" ", ",");
2709 TObjArray *fextra = extra.Tokenize(",");
2710 TIter nextx(fextra);
2712 while ((obj=nextx())) {
2713 if (aodfiles.Contains(obj->GetName())) continue;
2714 if (outputfiles.Contains(obj->GetName())) continue;
2715 if (sextra.Contains(obj->GetName())) continue;
2716 if (!sextra.IsNull()) sextra += ",";
2717 sextra += obj->GetName();
2720 if (stype.Contains("ext")) {
2721 if (!files.IsNull()) files += ",";
2725 if (stype == "ext") return files.Data();
2727 if (!fTerminateFiles.IsNull()) {
2728 fTerminateFiles.Strip();
2729 fTerminateFiles.ReplaceAll(" ",",");
2730 TObjArray *fextra = fTerminateFiles.Tokenize(",");
2731 TIter nextx(fextra);
2733 while ((obj=nextx())) {
2734 if (aodfiles.Contains(obj->GetName())) continue;
2735 if (outputfiles.Contains(obj->GetName())) continue;
2736 if (termfiles.Contains(obj->GetName())) continue;
2737 if (sextra.Contains(obj->GetName())) continue;
2738 if (!termfiles.IsNull()) termfiles += ",";
2739 termfiles += obj->GetName();
2743 if (stype.Contains("ter")) {
2744 if (!files.IsNull() && !termfiles.IsNull()) {
2749 return files.Data();
2752 //______________________________________________________________________________
2753 Bool_t AliAnalysisAlien::Submit()
2755 // Submit all master jobs.
2756 Int_t nmasterjobs = fInputFiles->GetEntries();
2757 Long_t tshoot = gSystem->Now();
2758 if (!fNsubmitted && !SubmitNext()) return kFALSE;
2759 while (fNsubmitted < nmasterjobs) {
2760 Long_t now = gSystem->Now();
2761 if ((now-tshoot)>30000) {
2763 if (!SubmitNext()) return kFALSE;
2769 //______________________________________________________________________________
2770 Bool_t AliAnalysisAlien::SubmitMerging()
2772 // Submit all merging jobs.
2773 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2774 gGrid->Cd(fGridOutputDir);
2775 TString mergeJDLName = fExecutable;
2776 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2777 Int_t ntosubmit = fInputFiles->GetEntries();
2778 for (Int_t i=0; i<ntosubmit; i++) {
2779 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2780 runOutDir.ReplaceAll(".xml", "");
2781 if (fOutputToRunNo) {
2782 // The output directory is the run number
2783 printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
2784 runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
2786 // The output directory is the master number in 3 digits format
2787 printf("### Submitting merging job for master <%03d>\n", i);
2788 runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
2790 // Check now the number of merging stages.
2791 TObjArray *list = fOutputFiles.Tokenize(",");
2795 while((str=(TObjString*)next())) {
2796 outputFile = str->GetString();
2797 Int_t index = outputFile.Index("@");
2798 if (index > 0) outputFile.Remove(index);
2799 if (!fMergeExcludes.Contains(outputFile)) break;
2802 Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, mergeJDLName);
2803 if (!done) return kFALSE;
2805 if (!ntosubmit) return kTRUE;
2806 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
2807 \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
2808 \n ##################################################################################");
2809 gSystem->Exec("aliensh");
2813 //______________________________________________________________________________
2814 Bool_t AliAnalysisAlien::SubmitNext()
2816 // Submit next bunch of master jobs if the queue is free. The first master job is
2817 // submitted right away, while the next will not be unless the previous was split.
2818 // The plugin will not submit new master jobs if there are more that 500 jobs in
2820 static Bool_t iscalled = kFALSE;
2821 static Int_t firstmaster = 0;
2822 static Int_t lastmaster = 0;
2823 static Int_t npermaster = 0;
2824 if (iscalled) return kTRUE;
2826 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2827 Int_t ntosubmit = 0;
2830 Int_t nmasterjobs = fInputFiles->GetEntries();
2833 if (!IsUseSubmitPolicy()) {
2835 Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
2836 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
2837 ntosubmit = nmasterjobs;
2840 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
2841 printf("=== master %d: %s\n", lastmaster, status.Data());
2842 // If last master not split, just return
2843 if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
2844 // No more than 100 waiting jobs
2845 if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
2846 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
2847 if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
2848 if (!ntosubmit) ntosubmit = 1;
2849 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
2850 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2852 for (Int_t i=0; i<ntosubmit; i++) {
2853 // Submit for a range of enumeration of runs.
2854 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
2856 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2857 runOutDir.ReplaceAll(".xml", "");
2859 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2861 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
2862 printf("********* %s\n",query.Data());
2863 res = gGrid->Command(query);
2865 TString cjobId1 = res->GetKey(0,"jobId");
2866 if (!cjobId1.Length()) {
2870 Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2873 Info("StartAnalysis", "\n_______________________________________________________________________ \
2874 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2875 \n_______________________________________________________________________",
2876 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
2879 lastmaster = cjobId1.Atoi();
2880 if (!firstmaster) firstmaster = lastmaster;
2885 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2893 //______________________________________________________________________________
2894 void AliAnalysisAlien::WriteAnalysisFile()
2896 // Write current analysis manager into the file <analysisFile>
2897 TString analysisFile = fExecutable;
2898 analysisFile.ReplaceAll(".sh", ".root");
2899 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2900 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2901 if (!mgr || !mgr->IsInitialized()) {
2902 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2905 // Check analysis type
2907 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
2908 handler = (TObject*)mgr->GetInputEventHandler();
2910 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
2911 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
2913 TDirectory *cdir = gDirectory;
2914 TFile *file = TFile::Open(analysisFile, "RECREATE");
2916 // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
2917 if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
2918 // Unless merging makes no sense
2919 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
2922 // Enable termination for local jobs
2923 mgr->SetSkipTerminate(kFALSE);
2925 if (cdir) cdir->cd();
2926 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
2928 Bool_t copy = kTRUE;
2929 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2932 TString workdir = gGrid->GetHomeDirectory();
2933 workdir += fGridWorkingDir;
2934 Info("WriteAnalysisFile", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
2935 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
2936 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
2940 //______________________________________________________________________________
2941 void AliAnalysisAlien::WriteAnalysisMacro()
2943 // Write the analysis macro that will steer the analysis in grid mode.
2944 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2946 out.open(fAnalysisMacro.Data(), ios::out);
2948 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2951 Bool_t hasSTEERBase = kFALSE;
2952 Bool_t hasESD = kFALSE;
2953 Bool_t hasAOD = kFALSE;
2954 Bool_t hasANALYSIS = kFALSE;
2955 Bool_t hasANALYSISalice = kFALSE;
2956 Bool_t hasCORRFW = kFALSE;
2957 TString func = fAnalysisMacro;
2958 TString type = "ESD";
2959 TString comment = "// Analysis using ";
2960 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2961 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2965 if (type!="AOD" && fFriendChainName!="") {
2966 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2969 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2970 else comment += " data";
2971 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2972 func.ReplaceAll(".C", "");
2973 out << "void " << func.Data() << "()" << endl;
2975 out << comment.Data() << endl;
2976 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2977 out << " TStopwatch timer;" << endl;
2978 out << " timer.Start();" << endl << endl;
2979 // Change temp directory to current one
2980 out << "// Set temporary merging directory to current one" << endl;
2981 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
2982 // Reset existing include path
2983 out << "// Reset existing include path and add current directory first in the search" << endl;
2984 out << " gSystem->SetIncludePath(\"-I.\");" << endl;
2985 if (!fExecutableCommand.Contains("aliroot")) {
2986 out << "// load base root libraries" << endl;
2987 out << " gSystem->Load(\"libTree\");" << endl;
2988 out << " gSystem->Load(\"libGeom\");" << endl;
2989 out << " gSystem->Load(\"libVMC\");" << endl;
2990 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
2991 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
2993 if (fAdditionalRootLibs.Length()) {
2994 // in principle libtree /lib geom libvmc etc. can go into this list, too
2995 out << "// Add aditional libraries" << endl;
2996 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2999 while((str=(TObjString*)next())) {
3000 if (str->GetString().Contains(".so"))
3001 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3003 if (list) delete list;
3005 out << "// Load analysis framework libraries" << endl;
3006 TString setupPar = "AliAnalysisAlien::SetupPar";
3008 if (!fExecutableCommand.Contains("aliroot")) {
3009 out << " gSystem->Load(\"libSTEERBase\");" << endl;
3010 out << " gSystem->Load(\"libESD\");" << endl;
3011 out << " gSystem->Load(\"libAOD\");" << endl;
3013 out << " gSystem->Load(\"libANALYSIS\");" << endl;
3014 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3015 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3017 TIter next(fPackages);
3020 while ((obj=next())) {
3021 pkgname = obj->GetName();
3022 if (pkgname == "STEERBase" ||
3023 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3024 if (pkgname == "ESD" ||
3025 pkgname == "ESD.par") hasESD = kTRUE;
3026 if (pkgname == "AOD" ||
3027 pkgname == "AOD.par") hasAOD = kTRUE;
3028 if (pkgname == "ANALYSIS" ||
3029 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
3030 if (pkgname == "ANALYSISalice" ||
3031 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3032 if (pkgname == "CORRFW" ||
3033 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
3035 if (hasANALYSISalice) setupPar = "SetupPar";
3036 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
3037 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3038 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
3039 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
3040 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
3041 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
3042 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
3043 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3044 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3045 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3046 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3047 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3048 out << "// Compile other par packages" << endl;
3050 while ((obj=next())) {
3051 pkgname = obj->GetName();
3052 if (pkgname == "STEERBase" ||
3053 pkgname == "STEERBase.par" ||
3055 pkgname == "ESD.par" ||
3057 pkgname == "AOD.par" ||
3058 pkgname == "ANALYSIS" ||
3059 pkgname == "ANALYSIS.par" ||
3060 pkgname == "ANALYSISalice" ||
3061 pkgname == "ANALYSISalice.par" ||
3062 pkgname == "CORRFW" ||
3063 pkgname == "CORRFW.par") continue;
3064 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3067 out << "// include path" << endl;
3068 // Get the include path from the interpreter and remove entries pointing to AliRoot
3069 out << " TString intPath = gInterpreter->GetIncludePath();" << endl;
3070 out << " TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3071 out << " TIter nextpath(listpaths);" << endl;
3072 out << " TObjString *pname;" << endl;
3073 out << " while ((pname=(TObjString*)nextpath())) {" << endl;
3074 out << " TString current = pname->GetName();" << endl;
3075 out << " if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3076 out << " gSystem->AddIncludePath(current);" << endl;
3077 out << " }" << endl;
3078 out << " if (listpaths) delete listpaths;" << endl;
3079 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3080 out << " gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3081 out << " printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3082 if (fAdditionalLibs.Length()) {
3083 out << "// Add aditional AliRoot libraries" << endl;
3084 TObjArray *list = fAdditionalLibs.Tokenize(" ");
3087 while((str=(TObjString*)next())) {
3088 if (str->GetString().Contains(".so"))
3089 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3090 if (str->GetString().Contains(".par"))
3091 out << " if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
3093 if (list) delete list;
3096 out << "// analysis source to be compiled at runtime (if any)" << endl;
3097 if (fAnalysisSource.Length()) {
3098 TObjArray *list = fAnalysisSource.Tokenize(" ");
3101 while((str=(TObjString*)next())) {
3102 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3104 if (list) delete list;
3107 // out << " printf(\"Currently load libraries:\\n\");" << endl;
3108 // out << " printf(\"%s\\n\", gSystem->GetLibraries());" << endl;
3109 if (fFastReadOption) {
3110 Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. This may skip some files that could be accessed !!! \
3111 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3112 out << "// fast xrootd reading enabled" << endl;
3113 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3114 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3115 out << " gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3116 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3117 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3118 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3120 out << "// connect to AliEn and make the chain" << endl;
3121 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
3122 out << "// read the analysis manager from file" << endl;
3123 TString analysisFile = fExecutable;
3124 analysisFile.ReplaceAll(".sh", ".root");
3125 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
3126 out << " if (!file) return;" << endl;
3127 out << " TIter nextkey(file->GetListOfKeys());" << endl;
3128 out << " AliAnalysisManager *mgr = 0;" << endl;
3129 out << " TKey *key;" << endl;
3130 out << " while ((key=(TKey*)nextkey())) {" << endl;
3131 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
3132 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
3133 out << " };" << endl;
3134 out << " if (!mgr) {" << endl;
3135 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file " << analysisFile <<"\");" << endl;
3136 out << " return;" << endl;
3137 out << " }" << endl << endl;
3138 out << " mgr->PrintStatus();" << endl;
3139 if (AliAnalysisManager::GetAnalysisManager()) {
3140 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3141 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3143 if (TestBit(AliAnalysisGrid::kTest))
3144 out << " AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3146 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3149 if (IsUsingTags()) {
3150 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
3152 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
3154 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
3155 out << " timer.Stop();" << endl;
3156 out << " timer.Print();" << endl;
3157 out << "}" << endl << endl;
3158 if (IsUsingTags()) {
3159 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
3161 out << "// Create a chain using tags from the xml file." << endl;
3162 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
3163 out << " if (!coll) {" << endl;
3164 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3165 out << " return NULL;" << endl;
3166 out << " }" << endl;
3167 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
3168 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
3169 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
3170 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
3171 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
3172 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
3173 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
3174 out << " // Check if the cuts configuration file was provided" << endl;
3175 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
3176 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
3177 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3178 out << " }" << endl;
3179 if (fFriendChainName=="") {
3180 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3182 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
3183 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
3184 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
3186 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
3187 out << " chain->ls();" << endl;
3188 out << " return chain;" << endl;
3189 out << "}" << endl << endl;
3190 if (gSystem->AccessPathName("ConfigureCuts.C")) {
3191 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
3192 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
3193 msg += " AliLHCTagCuts *lhcCuts,\n";
3194 msg += " AliDetectorTagCuts *detCuts,\n";
3195 msg += " AliEventTagCuts *evCuts)";
3196 Info("WriteAnalysisMacro", "%s", msg.Data());
3199 if (!IsUsingTags() || fFriendChainName!="") {
3200 out <<"//________________________________________________________________________________" << endl;
3201 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
3203 out << "// Create a chain using url's from xml file" << endl;
3204 out << " TString filename;" << endl;
3205 out << " Int_t run = 0;" << endl;
3206 out << " TString treename = type;" << endl;
3207 out << " treename.ToLower();" << endl;
3208 out << " treename += \"Tree\";" << endl;
3209 out << " printf(\"***************************************\\n\");" << endl;
3210 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
3211 out << " printf(\"***************************************\\n\");" << endl;
3212 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
3213 out << " if (!coll) {" << endl;
3214 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3215 out << " return NULL;" << endl;
3216 out << " }" << endl;
3217 out << " AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();" << endl;
3218 out << " TChain *chain = new TChain(treename);" << endl;
3219 if(fFriendChainName!="") {
3220 out << " TChain *chainFriend = new TChain(treename);" << endl;
3222 out << " coll->Reset();" << endl;
3223 out << " while (coll->Next()) {" << endl;
3224 out << " filename = coll->GetTURL("");" << endl;
3225 out << " if (mgr) {" << endl;
3226 out << " Int_t nrun = AliAnalysisManager::GetRunFromAlienPath(filename);" << endl;
3227 out << " if (nrun && nrun != run) {" << endl;
3228 out << " printf(\"### Run number detected from chain: %d\\n\", nrun);" << endl;
3229 out << " mgr->SetRunFromPath(nrun);" << endl;
3230 out << " run = nrun;" << endl;
3231 out << " }" << endl;
3232 out << " }" << endl;
3233 out << " chain->Add(filename);" << endl;
3234 if(fFriendChainName!="") {
3235 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
3236 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3237 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3238 out << " chainFriend->Add(fileFriend.Data());" << endl;
3240 out << " }" << endl;
3241 out << " if (!chain->GetNtrees()) {" << endl;
3242 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
3243 out << " return NULL;" << endl;
3244 out << " }" << endl;
3245 if(fFriendChainName!="") {
3246 out << " chain->AddFriend(chainFriend);" << endl;
3248 out << " return chain;" << endl;
3249 out << "}" << endl << endl;
3251 if (hasANALYSISalice) {
3252 out <<"//________________________________________________________________________________" << endl;
3253 out << "Bool_t SetupPar(const char *package) {" << endl;
3254 out << "// Compile the package and set it up." << endl;
3255 out << " TString pkgdir = package;" << endl;
3256 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3257 out << " gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3258 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
3259 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
3260 out << " // Check for BUILD.sh and execute" << endl;
3261 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3262 out << " printf(\"*******************************\\n\");" << endl;
3263 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
3264 out << " printf(\"*******************************\\n\");" << endl;
3265 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3266 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3267 out << " gSystem->ChangeDirectory(cdir);" << endl;
3268 out << " return kFALSE;" << endl;
3269 out << " }" << endl;
3270 out << " } else {" << endl;
3271 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3272 out << " gSystem->ChangeDirectory(cdir);" << endl;
3273 out << " return kFALSE;" << endl;
3274 out << " }" << endl;
3275 out << " // Check for SETUP.C and execute" << endl;
3276 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3277 out << " printf(\"*******************************\\n\");" << endl;
3278 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
3279 out << " printf(\"*******************************\\n\");" << endl;
3280 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3281 out << " } else {" << endl;
3282 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3283 out << " gSystem->ChangeDirectory(cdir);" << endl;
3284 out << " return kFALSE;" << endl;
3285 out << " }" << endl;
3286 out << " // Restore original workdir" << endl;
3287 out << " gSystem->ChangeDirectory(cdir);" << endl;
3288 out << " return kTRUE;" << endl;
3291 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
3293 Bool_t copy = kTRUE;
3294 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3297 TString workdir = gGrid->GetHomeDirectory();
3298 workdir += fGridWorkingDir;
3299 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
3300 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
3301 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
3302 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
3303 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
3305 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
3306 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
3310 //______________________________________________________________________________
3311 void AliAnalysisAlien::WriteMergingMacro()
3313 // Write a macro to merge the outputs per master job.
3314 if (!fMergeViaJDL) return;
3315 if (!fOutputFiles.Length()) {
3316 Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3319 TString mergingMacro = fExecutable;
3320 mergingMacro.ReplaceAll(".sh","_merge.C");
3321 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3322 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3324 out.open(mergingMacro.Data(), ios::out);
3326 Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3329 Bool_t hasSTEERBase = kFALSE;
3330 Bool_t hasESD = kFALSE;
3331 Bool_t hasAOD = kFALSE;
3332 Bool_t hasANALYSIS = kFALSE;
3333 Bool_t hasANALYSISalice = kFALSE;
3334 Bool_t hasCORRFW = kFALSE;
3335 TString func = mergingMacro;
3337 func.ReplaceAll(".C", "");
3338 out << "void " << func.Data() << "(const char *dir, Int_t stage=0, Int_t laststage=0)" << endl;
3340 out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
3341 out << " TStopwatch timer;" << endl;
3342 out << " timer.Start();" << endl << endl;
3343 // Reset existing include path
3344 out << "// Reset existing include path and add current directory first in the search" << endl;
3345 out << " gSystem->SetIncludePath(\"-I.\");" << endl;
3346 if (!fExecutableCommand.Contains("aliroot")) {
3347 out << "// load base root libraries" << endl;
3348 out << " gSystem->Load(\"libTree\");" << endl;
3349 out << " gSystem->Load(\"libGeom\");" << endl;
3350 out << " gSystem->Load(\"libVMC\");" << endl;
3351 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
3352 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
3354 if (fAdditionalRootLibs.Length()) {
3355 // in principle libtree /lib geom libvmc etc. can go into this list, too
3356 out << "// Add aditional libraries" << endl;
3357 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3360 while((str=(TObjString*)next())) {
3361 if (str->GetString().Contains(".so"))
3362 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3364 if (list) delete list;
3366 out << "// Load analysis framework libraries" << endl;
3368 if (!fExecutableCommand.Contains("aliroot")) {
3369 out << " gSystem->Load(\"libSTEERBase\");" << endl;
3370 out << " gSystem->Load(\"libESD\");" << endl;
3371 out << " gSystem->Load(\"libAOD\");" << endl;
3373 out << " gSystem->Load(\"libANALYSIS\");" << endl;
3374 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3375 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3377 TIter next(fPackages);
3380 TString setupPar = "AliAnalysisAlien::SetupPar";
3381 while ((obj=next())) {
3382 pkgname = obj->GetName();
3383 if (pkgname == "STEERBase" ||
3384 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3385 if (pkgname == "ESD" ||
3386 pkgname == "ESD.par") hasESD = kTRUE;
3387 if (pkgname == "AOD" ||
3388 pkgname == "AOD.par") hasAOD = kTRUE;
3389 if (pkgname == "ANALYSIS" ||
3390 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
3391 if (pkgname == "ANALYSISalice" ||
3392 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3393 if (pkgname == "CORRFW" ||
3394 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
3396 if (hasANALYSISalice) setupPar = "SetupPar";
3397 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
3398 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3399 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
3400 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
3401 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
3402 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
3403 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
3404 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3405 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3406 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3407 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3408 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3409 out << "// Compile other par packages" << endl;
3411 while ((obj=next())) {
3412 pkgname = obj->GetName();
3413 if (pkgname == "STEERBase" ||
3414 pkgname == "STEERBase.par" ||
3416 pkgname == "ESD.par" ||
3418 pkgname == "AOD.par" ||
3419 pkgname == "ANALYSIS" ||
3420 pkgname == "ANALYSIS.par" ||
3421 pkgname == "ANALYSISalice" ||
3422 pkgname == "ANALYSISalice.par" ||
3423 pkgname == "CORRFW" ||
3424 pkgname == "CORRFW.par") continue;
3425 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3428 out << "// include path" << endl;
3429 // Get the include path from the interpreter and remove entries pointing to AliRoot
3430 out << " TString intPath = gInterpreter->GetIncludePath();" << endl;
3431 out << " TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3432 out << " TIter nextpath(listpaths);" << endl;
3433 out << " TObjString *pname;" << endl;
3434 out << " while ((pname=(TObjString*)nextpath())) {" << endl;
3435 out << " TString current = pname->GetName();" << endl;
3436 out << " if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3437 out << " gSystem->AddIncludePath(current);" << endl;
3438 out << " }" << endl;
3439 out << " if (listpaths) delete listpaths;" << endl;
3440 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3441 out << " gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3442 out << " printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3443 if (fAdditionalLibs.Length()) {
3444 out << "// Add aditional AliRoot libraries" << endl;
3445 TObjArray *list = fAdditionalLibs.Tokenize(" ");
3448 while((str=(TObjString*)next())) {
3449 if (str->GetString().Contains(".so"))
3450 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3452 if (list) delete list;
3455 out << "// Analysis source to be compiled at runtime (if any)" << endl;
3456 if (fAnalysisSource.Length()) {
3457 TObjArray *list = fAnalysisSource.Tokenize(" ");
3460 while((str=(TObjString*)next())) {
3461 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3463 if (list) delete list;
3467 if (fFastReadOption) {
3468 Warning("WriteMergingMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid merging jobs. Note that this may skip some files that could be accessed !!!");
3469 out << "// fast xrootd reading enabled" << endl;
3470 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3471 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3472 out << " gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3473 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3474 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3475 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3477 // Change temp directory to current one
3478 out << "// Set temporary merging directory to current one" << endl;
3479 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
3480 out << "// Connect to AliEn" << endl;
3481 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
3482 out << " TString outputDir = dir;" << endl;
3483 out << " TString outputFiles = \"" << GetListOfFiles("out") << "\";" << endl;
3484 out << " TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
3485 out << " TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
3486 out << " TIter *iter = new TIter(list);" << endl;
3487 out << " TObjString *str;" << endl;
3488 out << " TString outputFile;" << endl;
3489 out << " Bool_t merged = kTRUE;" << endl;
3490 out << " while((str=(TObjString*)iter->Next())) {" << endl;
3491 out << " outputFile = str->GetString();" << endl;
3492 out << " if (outputFile.Contains(\"*\")) continue;" << endl;
3493 out << " Int_t index = outputFile.Index(\"@\");" << endl;
3494 out << " if (index > 0) outputFile.Remove(index);" << endl;
3495 out << " // Skip already merged outputs" << endl;
3496 out << " if (!gSystem->AccessPathName(outputFile)) {" << endl;
3497 out << " printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
3498 out << " continue;" << endl;
3499 out << " }" << endl;
3500 out << " if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
3501 out << " merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage);" << endl;
3502 out << " if (!merged) {" << endl;
3503 out << " printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
3504 out << " return;" << endl;
3505 out << " }" << endl;
3506 out << " }" << endl;
3507 out << " // all outputs merged, validate" << endl;
3508 out << " ofstream out;" << endl;
3509 out << " out.open(\"outputs_valid\", ios::out);" << endl;
3510 out << " out.close();" << endl;
3511 out << " // read the analysis manager from file" << endl;
3512 TString analysisFile = fExecutable;
3513 analysisFile.ReplaceAll(".sh", ".root");
3514 out << " if (laststage<10000) return;" << endl;
3515 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
3516 out << " if (!file) return;" << endl;
3517 out << " TIter nextkey(file->GetListOfKeys());" << endl;
3518 out << " AliAnalysisManager *mgr = 0;" << endl;
3519 out << " TKey *key;" << endl;
3520 out << " while ((key=(TKey*)nextkey())) {" << endl;
3521 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
3522 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
3523 out << " };" << endl;
3524 out << " if (!mgr) {" << endl;
3525 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
3526 out << " return;" << endl;
3527 out << " }" << endl << endl;
3528 out << " mgr->SetRunFromPath(mgr->GetRunFromAlienPath(dir));" << endl;
3529 out << " mgr->SetSkipTerminate(kFALSE);" << endl;
3530 out << " mgr->PrintStatus();" << endl;
3531 if (AliAnalysisManager::GetAnalysisManager()) {
3532 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3533 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3535 if (TestBit(AliAnalysisGrid::kTest))
3536 out << " AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3538 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3541 out << " TTree *tree = NULL;" << endl;
3542 out << " mgr->StartAnalysis(\"gridterminate\", tree);" << endl;
3543 out << "}" << endl << endl;
3544 if (hasANALYSISalice) {
3545 out <<"//________________________________________________________________________________" << endl;
3546 out << "Bool_t SetupPar(const char *package) {" << endl;
3547 out << "// Compile the package and set it up." << endl;
3548 out << " TString pkgdir = package;" << endl;
3549 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3550 out << " gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3551 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
3552 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
3553 out << " // Check for BUILD.sh and execute" << endl;
3554 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3555 out << " printf(\"*******************************\\n\");" << endl;
3556 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
3557 out << " printf(\"*******************************\\n\");" << endl;
3558 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3559 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3560 out << " gSystem->ChangeDirectory(cdir);" << endl;
3561 out << " return kFALSE;" << endl;
3562 out << " }" << endl;
3563 out << " } else {" << endl;
3564 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3565 out << " gSystem->ChangeDirectory(cdir);" << endl;
3566 out << " return kFALSE;" << endl;
3567 out << " }" << endl;
3568 out << " // Check for SETUP.C and execute" << endl;
3569 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3570 out << " printf(\"*******************************\\n\");" << endl;
3571 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
3572 out << " printf(\"*******************************\\n\");" << endl;
3573 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3574 out << " } else {" << endl;
3575 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3576 out << " gSystem->ChangeDirectory(cdir);" << endl;
3577 out << " return kFALSE;" << endl;
3578 out << " }" << endl;
3579 out << " // Restore original workdir" << endl;
3580 out << " gSystem->ChangeDirectory(cdir);" << endl;
3581 out << " return kTRUE;" << endl;
3585 Bool_t copy = kTRUE;
3586 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3589 TString workdir = gGrid->GetHomeDirectory();
3590 workdir += fGridWorkingDir;
3591 if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
3592 Info("WriteMergingMacro", "\n##### Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
3593 TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
3597 //______________________________________________________________________________
3598 Bool_t AliAnalysisAlien::SetupPar(const char *package)
3600 // Compile the par file archive pointed by <package>. This must be present in the current directory.
3601 // Note that for loading the compiled library. The current directory should have precedence in
3603 TString pkgdir = package;
3604 pkgdir.ReplaceAll(".par","");
3605 gSystem->Exec(TString::Format("tar xzf %s.par", pkgdir.Data()));
3606 TString cdir = gSystem->WorkingDirectory();
3607 gSystem->ChangeDirectory(pkgdir);
3608 // Check for BUILD.sh and execute
3609 if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
3610 printf("**************************************************\n");
3611 printf("*** Building PAR archive %s\n", package);
3612 printf("**************************************************\n");
3613 if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
3614 ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
3615 gSystem->ChangeDirectory(cdir);
3619 ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
3620 gSystem->ChangeDirectory(cdir);
3623 // Check for SETUP.C and execute
3624 if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
3625 printf("**************************************************\n");
3626 printf("*** Setup PAR archive %s\n", package);
3627 printf("**************************************************\n");
3628 gROOT->Macro("PROOF-INF/SETUP.C");
3629 printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
3631 ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
3632 gSystem->ChangeDirectory(cdir);
3635 // Restore original workdir
3636 gSystem->ChangeDirectory(cdir);
3640 //______________________________________________________________________________
3641 void AliAnalysisAlien::WriteExecutable()
3643 // Generate the alien executable script.
3644 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3646 out.open(fExecutable.Data(), ios::out);
3648 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
3651 out << "#!/bin/bash" << endl;
3652 // Make sure we can properly compile par files
3653 out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3654 out << "echo \"=========================================\"" << endl;
3655 out << "echo \"############## PATH : ##############\"" << endl;
3656 out << "echo $PATH" << endl;
3657 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3658 out << "echo $LD_LIBRARY_PATH" << endl;
3659 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3660 out << "echo $ROOTSYS" << endl;
3661 out << "echo \"############## which root : ##############\"" << endl;
3662 out << "which root" << endl;
3663 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3664 out << "echo $ALICE_ROOT" << endl;
3665 out << "echo \"############## which aliroot : ##############\"" << endl;
3666 out << "which aliroot" << endl;
3667 out << "echo \"############## system limits : ##############\"" << endl;
3668 out << "ulimit -a" << endl;
3669 out << "echo \"############## memory : ##############\"" << endl;
3670 out << "free -m" << endl;
3671 out << "echo \"=========================================\"" << endl << endl;
3672 out << fExecutableCommand << " ";
3673 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
3674 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
3675 out << "echo \"############## memory after: ##############\"" << endl;
3676 out << "free -m" << endl;
3678 Bool_t copy = kTRUE;
3679 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3682 TString workdir = gGrid->GetHomeDirectory();
3683 TString bindir = Form("%s/bin", workdir.Data());
3684 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
3685 workdir += fGridWorkingDir;
3686 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
3687 if (FileExists(executable)) gGrid->Rm(executable);
3688 Info("WriteExecutable", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
3689 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
3693 //______________________________________________________________________________
3694 void AliAnalysisAlien::WriteMergeExecutable()
3696 // Generate the alien executable script for the merging job.
3697 if (!fMergeViaJDL) return;
3698 TString mergeExec = fExecutable;
3699 mergeExec.ReplaceAll(".sh", "_merge.sh");
3700 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3702 out.open(mergeExec.Data(), ios::out);
3704 Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
3707 out << "#!/bin/bash" << endl;
3708 // Make sure we can properly compile par files
3709 out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3710 out << "echo \"=========================================\"" << endl;
3711 out << "echo \"############## PATH : ##############\"" << endl;
3712 out << "echo $PATH" << endl;
3713 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3714 out << "echo $LD_LIBRARY_PATH" << endl;
3715 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3716 out << "echo $ROOTSYS" << endl;
3717 out << "echo \"############## which root : ##############\"" << endl;
3718 out << "which root" << endl;
3719 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3720 out << "echo $ALICE_ROOT" << endl;
3721 out << "echo \"############## which aliroot : ##############\"" << endl;
3722 out << "which aliroot" << endl;
3723 out << "echo \"############## system limits : ##############\"" << endl;
3724 out << "ulimit -a" << endl;
3725 out << "echo \"############## memory : ##############\"" << endl;
3726 out << "free -m" << endl;
3727 out << "echo \"=========================================\"" << endl << endl;
3728 TString mergeMacro = fExecutable;
3729 mergeMacro.ReplaceAll(".sh", "_merge.C");
3730 if (IsOneStageMerging())
3731 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
3733 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2,$3)\"" << endl;
3734 out << fExecutableCommand << " " << "$ARG" << endl;
3735 out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
3736 out << "echo \"############## memory after: ##############\"" << endl;
3737 out << "free -m" << endl;
3739 Bool_t copy = kTRUE;
3740 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3743 TString workdir = gGrid->GetHomeDirectory();
3744 TString bindir = Form("%s/bin", workdir.Data());
3745 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
3746 workdir += fGridWorkingDir;
3747 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
3748 if (FileExists(executable)) gGrid->Rm(executable);
3749 Info("WriteMergeExecutable", "\n##### Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
3750 TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
3754 //______________________________________________________________________________
3755 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
3757 // Write the production file to be submitted by LPM manager. The format is:
3758 // First line: full_path_to_jdl estimated_no_subjobs_per_master
3759 // Next lines: full_path_to_dataset XXX (XXX is a string)
3760 // To submit, one has to: submit jdl XXX for all lines
3762 out.open(filename, ios::out);
3764 Error("WriteProductionFile", "Bad file name: %s", filename);
3768 if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice"))
3769 workdir = gGrid->GetHomeDirectory();
3770 workdir += fGridWorkingDir;
3771 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
3772 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
3773 out << locjdl << " " << njobspermaster << endl;
3774 Int_t nmasterjobs = fInputFiles->GetEntries();
3775 for (Int_t i=0; i<nmasterjobs; i++) {
3776 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3777 runOutDir.ReplaceAll(".xml", "");
3779 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
3781 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
3784 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
3785 if (FileExists(filename)) gGrid->Rm(filename);
3786 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
3790 //______________________________________________________________________________
3791 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
3793 // Generate the alien validation script.
3794 // Generate the validation script
3796 if (fValidationScript.IsNull()) {
3797 fValidationScript = fExecutable;
3798 fValidationScript.ReplaceAll(".sh", "_validation.sh");
3800 TString validationScript = fValidationScript;
3801 if (merge) validationScript.ReplaceAll(".sh", "_merge.sh");
3803 Error("WriteValidationScript", "Alien connection required");
3806 if (!fTerminateFiles.IsNull()) {
3807 fTerminateFiles.Strip();
3808 fTerminateFiles.ReplaceAll(" ",",");
3810 TString outStream = "";
3811 if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
3812 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3814 out.open(validationScript, ios::out);
3815 out << "#!/bin/bash" << endl;
3816 out << "##################################################" << endl;
3817 out << "validateout=`dirname $0`" << endl;
3818 out << "validatetime=`date`" << endl;
3819 out << "validated=\"0\";" << endl;
3820 out << "error=0" << endl;
3821 out << "if [ -z $validateout ]" << endl;
3822 out << "then" << endl;
3823 out << " validateout=\".\"" << endl;
3824 out << "fi" << endl << endl;
3825 out << "cd $validateout;" << endl;
3826 out << "validateworkdir=`pwd`;" << endl << endl;
3827 out << "echo \"*******************************************************\"" << outStream << endl;
3828 out << "echo \"* Automatically generated validation script *\"" << outStream << endl;
3830 out << "echo \"* Time: $validatetime \"" << outStream << endl;
3831 out << "echo \"* Dir: $validateout\"" << outStream << endl;
3832 out << "echo \"* Workdir: $validateworkdir\"" << outStream << endl;
3833 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3834 out << "ls -la ./" << outStream << endl;
3835 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl << endl;
3836 out << "##################################################" << endl;
3839 out << "if [ ! -f stderr ] ; then" << endl;
3840 out << " error=1" << endl;
3841 out << " echo \"* ########## Job not validated - no stderr ###\" " << outStream << endl;
3842 out << " echo \"Error = $error\" " << outStream << endl;
3843 out << "fi" << endl;
3845 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
3846 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
3847 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
3848 out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
3851 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
3852 out << " error=1" << endl;
3853 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << outStream << endl;
3854 out << " echo \"$parArch\" " << outStream << endl;
3855 out << " echo \"Error = $error\" " << outStream << endl;
3856 out << "fi" << endl;
3858 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
3859 out << " error=1" << endl;
3860 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << outStream << endl;
3861 out << " echo \"$segViol\" " << outStream << endl;
3862 out << " echo \"Error = $error\" " << outStream << endl;
3863 out << "fi" << endl;
3865 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
3866 out << " error=1" << endl;
3867 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << outStream << endl;
3868 out << " echo \"$segFault\" " << outStream << endl;
3869 out << " echo \"Error = $error\" " << outStream << endl;
3870 out << "fi" << endl;
3872 out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
3873 out << " error=1" << endl;
3874 out << " echo \"* ########## Job not validated - *** glibc detected *** ###\" " << outStream << endl;
3875 out << " echo \"$glibcErr\" " << outStream << endl;
3876 out << " echo \"Error = $error\" " << outStream << endl;
3877 out << "fi" << endl;
3879 // Part dedicated to the specific analyses running into the train
3881 TString outputFiles = fOutputFiles;
3882 if (merge && !fTerminateFiles.IsNull()) {
3884 outputFiles += fTerminateFiles;
3886 TObjArray *arr = outputFiles.Tokenize(",");
3889 while (!merge && (os=(TObjString*)next1())) {
3890 // No need to validate outputs produced by merging since the merging macro does this
3891 outputFile = os->GetString();
3892 Int_t index = outputFile.Index("@");
3893 if (index > 0) outputFile.Remove(index);
3894 if (fTerminateFiles.Contains(outputFile)) continue;
3895 if (outputFile.Contains("*")) continue;
3896 out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
3897 out << " error=1" << endl;
3898 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\"" << outStream << endl;
3899 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
3900 out << "fi" << endl;
3903 out << "if ! [ -f outputs_valid ] ; then" << endl;
3904 out << " error=1" << endl;
3905 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
3906 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
3907 out << "fi" << endl;
3909 out << "if [ $error = 0 ] ; then" << endl;
3910 out << " echo \"* ---------------- Job Validated ------------------*\"" << outStream << endl;
3911 if (!IsKeepLogs()) {
3912 out << " echo \"* === Logs std* will be deleted === \"" << endl;
3914 out << " rm -f std*" << endl;
3916 out << "fi" << endl;
3918 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3919 out << "echo \"*******************************************************\"" << outStream << endl;
3920 out << "cd -" << endl;
3921 out << "exit $error" << endl;
3923 Bool_t copy = kTRUE;
3924 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3927 TString workdir = gGrid->GetHomeDirectory();
3928 workdir += fGridWorkingDir;
3929 Info("WriteValidationScript", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
3930 if (FileExists(validationScript)) gGrid->Rm(validationScript);
3931 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));