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::AddIncludePath(const char *path)
368 // Add include path in the remote analysis macro.
370 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
371 else fIncludePath += Form("-I%s ", path);
374 //______________________________________________________________________________
375 void AliAnalysisAlien::AddRunNumber(Int_t run)
377 // Add a run number to the list of runs to be processed.
378 if (fRunNumbers.Length()) fRunNumbers += " ";
379 fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
382 //______________________________________________________________________________
383 void AliAnalysisAlien::AddRunNumber(const char* run)
385 // Add a run number to the list of runs to be processed.
386 if (fRunNumbers.Length()) fRunNumbers += " ";
390 //______________________________________________________________________________
391 void AliAnalysisAlien::AddDataFile(const char *lfn)
393 // Adds a data file to the input to be analysed. The file should be a valid LFN
394 // or point to an existing file in the alien workdir.
395 if (!fInputFiles) fInputFiles = new TObjArray();
396 fInputFiles->Add(new TObjString(lfn));
399 //______________________________________________________________________________
400 void AliAnalysisAlien::AddExternalPackage(const char *package)
402 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
403 if (fExternalPackages) fExternalPackages += " ";
404 fExternalPackages += package;
407 //______________________________________________________________________________
408 Bool_t AliAnalysisAlien::Connect()
410 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
411 if (gGrid && gGrid->IsConnected()) return kTRUE;
412 if (fProductionMode) return kTRUE;
414 Info("Connect", "Trying to connect to AliEn ...");
415 TGrid::Connect("alien://");
417 if (!gGrid || !gGrid->IsConnected()) {
418 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
421 fUser = gGrid->GetUser();
422 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
426 //______________________________________________________________________________
427 void AliAnalysisAlien::CdWork()
429 // Check validity of alien workspace. Create directory if possible.
431 Error("CdWork", "Alien connection required");
434 TString homedir = gGrid->GetHomeDirectory();
435 TString workdir = homedir + fGridWorkingDir;
436 if (DirectoryExists(workdir)) {
440 // Work directory not existing - create it
442 if (gGrid->Mkdir(workdir, "-p")) {
443 gGrid->Cd(fGridWorkingDir);
444 Info("CdWork", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
446 Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
447 workdir.Data(), homedir.Data());
448 fGridWorkingDir = "";
452 //______________________________________________________________________________
453 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
455 // Check if file copying is possible.
456 if (fProductionMode) return kTRUE;
458 Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
461 Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
462 \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
463 // Check if alien_CLOSE_SE is defined
464 TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
465 if (!closeSE.IsNull()) {
466 Info("CheckFileCopy", "Your current close storage is pointing to: \
467 \n alien_CLOSE_SE = \"%s\"", closeSE.Data());
469 Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
471 // Check if grid directory exists.
472 if (!DirectoryExists(alienpath)) {
473 Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
476 TFile f("plugin_test_copy", "RECREATE");
477 // User may not have write permissions to current directory
479 Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
480 gSystem->WorkingDirectory());
484 if (FileExists(Form("alien://%s/%s",alienpath, f.GetName()))) gGrid->Rm(Form("alien://%s/%s",alienpath, f.GetName()));
485 if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, f.GetName()))) {
486 Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
487 \n# 1. Make sure you have write permissions there. If this is the case: \
488 \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
489 \n# Do: export alien_CLOSE_SE=\"working_disk_SE\" \
490 \n# To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
491 \n# Redo token: rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
492 gSystem->Unlink(f.GetName());
495 gSystem->Unlink(f.GetName());
496 gGrid->Rm(Form("%s%s",alienpath,f.GetName()));
497 Info("CheckFileCopy", "### ...SUCCESS ###");
501 //______________________________________________________________________________
502 Bool_t AliAnalysisAlien::CheckInputData()
504 // Check validity of input data. If necessary, create xml files.
505 if (fProductionMode) return kTRUE;
506 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
507 if (!fGridDataDir.Length()) {
508 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
511 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
512 if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
513 TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode)
516 // Process declared files
517 Bool_t isCollection = kFALSE;
518 Bool_t isXml = kFALSE;
519 Bool_t useTags = kFALSE;
520 Bool_t checked = kFALSE;
521 if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
523 TString workdir = gGrid->GetHomeDirectory();
524 workdir += fGridWorkingDir;
527 TIter next(fInputFiles);
528 while ((objstr=(TObjString*)next())) {
531 file += objstr->GetString();
532 // Store full lfn path
533 if (FileExists(file)) objstr->SetString(file);
535 file = objstr->GetName();
536 if (!FileExists(objstr->GetName())) {
537 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
538 objstr->GetName(), workdir.Data());
542 Bool_t iscoll, isxml, usetags;
543 CheckDataType(file, iscoll, isxml, usetags);
546 isCollection = iscoll;
549 TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
551 if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
552 Error("CheckInputData", "Some conflict was found in the types of inputs");
558 // Process requested run numbers
559 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
560 // Check validity of alien data directory
561 if (!fGridDataDir.Length()) {
562 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
565 if (!DirectoryExists(fGridDataDir)) {
566 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
570 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
574 if (checked && !isXml) {
575 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
578 // Check validity of run number(s)
582 TString schunk, schunk2;
586 useTags = fDataPattern.Contains("tag");
587 TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
589 if (useTags != fDataPattern.Contains("tag")) {
590 Error("CheckInputData", "Cannot mix input files using/not using tags");
593 if (fRunNumbers.Length()) {
594 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
595 arr = fRunNumbers.Tokenize(" ");
597 while ((os=(TObjString*)next())) {
598 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
599 if (!DirectoryExists(path)) {
600 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
603 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
604 TString msg = "\n##### file: ";
606 msg += " type: xml_collection;";
607 if (useTags) msg += " using_tags: Yes";
608 else msg += " using_tags: No";
609 Info("CheckDataType", "%s", msg.Data());
610 if (fNrunsPerMaster<2) {
611 AddDataFile(Form("%s.xml", os->GetString().Data()));
614 if (((nruns-1)%fNrunsPerMaster) == 0) {
615 schunk = os->GetString();
617 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
618 schunk += Form("_%s.xml", os->GetString().Data());
624 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
625 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
626 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
627 if (!DirectoryExists(path)) {
628 // Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
631 path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
632 TString msg = "\n##### file: ";
634 msg += " type: xml_collection;";
635 if (useTags) msg += " using_tags: Yes";
636 else msg += " using_tags: No";
637 Info("CheckDataType", "%s", msg.Data());
638 if (fNrunsPerMaster<2) {
639 AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
642 if (((nruns-1)%fNrunsPerMaster) == 0) {
643 schunk = Form("%s%d", fRunPrefix.Data(),irun);
645 schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
646 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
659 //______________________________________________________________________________
660 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
662 // Create dataset for the grid data directory + run number.
663 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
665 Error("CreateDataset", "Cannot create dataset with no grid connection");
670 if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
671 TString workdir = gGrid->GetHomeDirectory();
672 workdir += fGridWorkingDir;
674 // Compose the 'find' command arguments
676 TString options = "-x collection ";
677 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
678 TString conditions = "";
683 TString schunk, schunk2;
684 TGridCollection *cbase=0, *cadd=0;
685 if (!fRunNumbers.Length() && !fRunRange[0]) {
686 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
687 // Make a single data collection from data directory.
689 if (!DirectoryExists(path)) {
690 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
694 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
695 else file = Form("%s.xml", gSystem->BaseName(path));
696 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
702 command += conditions;
703 printf("command: %s\n", command.Data());
704 TGridResult *res = gGrid->Command(command);
706 // Write standard output to file
707 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
708 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
709 Bool_t nullFile = kFALSE;
711 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
713 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
715 Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
720 Bool_t fileExists = FileExists(file);
721 if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
722 // Copy xml file to alien space
723 if (fileExists) gGrid->Rm(file);
724 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
725 if (!FileExists(file)) {
726 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
729 // Update list of files to be processed.
731 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
735 Bool_t nullResult = kTRUE;
736 if (fRunNumbers.Length()) {
737 TObjArray *arr = fRunNumbers.Tokenize(" ");
740 while ((os=(TObjString*)next())) {
741 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
742 if (!DirectoryExists(path)) continue;
744 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
745 else file = Form("%s.xml", os->GetString().Data());
746 // If local collection file does not exist, create it via 'find' command.
747 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
752 command += conditions;
753 TGridResult *res = gGrid->Command(command);
755 // Write standard output to file
756 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
757 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
758 Bool_t nullFile = kFALSE;
760 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
762 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
764 Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
765 fRunNumbers.ReplaceAll(os->GetString().Data(), "");
771 if (TestBit(AliAnalysisGrid::kTest)) break;
772 // Check if there is one run per master job.
773 if (fNrunsPerMaster<2) {
774 if (FileExists(file)) {
775 if (fOverwriteMode) gGrid->Rm(file);
777 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
781 // Copy xml file to alien space
782 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
783 if (!FileExists(file)) {
784 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
790 if (((nruns-1)%fNrunsPerMaster) == 0) {
791 schunk = os->GetString();
792 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
794 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
795 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
799 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
802 schunk += Form("_%s.xml", os->GetString().Data());
803 if (FileExists(schunk)) {
804 if (fOverwriteMode) gGrid->Rm(file);
806 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
810 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
811 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
812 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
813 if (!FileExists(schunk)) {
814 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
822 Error("CreateDataset", "No valid dataset corresponding to the query!");
826 // Process a full run range.
827 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
828 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
829 if (!DirectoryExists(path)) continue;
831 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
832 else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
833 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
834 if (fOverwriteMode) gGrid->Rm(file);
836 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
840 // If local collection file does not exist, create it via 'find' command.
841 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
846 command += conditions;
847 TGridResult *res = gGrid->Command(command);
849 // Write standard output to file
850 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
851 Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
852 Bool_t nullFile = kFALSE;
854 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
856 nullFile = (gSystem->Exec(Form("grep /event %s 2>/dev/null > /dev/null",file.Data()))==0)?kFALSE:kTRUE;
858 Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
864 if (TestBit(AliAnalysisGrid::kTest)) break;
865 // Check if there is one run per master job.
866 if (fNrunsPerMaster<2) {
867 if (FileExists(file)) {
868 if (fOverwriteMode) gGrid->Rm(file);
870 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
874 // Copy xml file to alien space
875 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
876 if (!FileExists(file)) {
877 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
882 // Check if the collection for the chunk exist locally.
883 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
884 if (FileExists(fInputFiles->At(nchunk)->GetName())) {
885 if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
888 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
889 if (((nruns-1)%fNrunsPerMaster) == 0) {
890 schunk = Form("%s%d", fRunPrefix.Data(), irun);
891 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
893 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
897 schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
898 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
902 if (FileExists(schunk)) {
903 if (fOverwriteMode) gGrid->Rm(schunk);
905 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
909 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
910 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
911 if (FileExists(schunk)) {
912 if (fOverwriteMode) gGrid->Rm(schunk);
914 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
918 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
919 if (!FileExists(schunk)) {
920 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
926 Error("CreateDataset", "No valid dataset corresponding to the query!");
933 //______________________________________________________________________________
934 Bool_t AliAnalysisAlien::CreateJDL()
936 // Generate a JDL file according to current settings. The name of the file is
937 // specified by fJDLName.
938 Bool_t error = kFALSE;
941 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
942 Bool_t generate = kTRUE;
943 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
945 Error("CreateJDL", "Alien connection required");
948 // Check validity of alien workspace
950 if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
951 if (!fProductionMode && !TestBit(AliAnalysisGrid::kTest)) CdWork();
952 workdir += fGridWorkingDir;
956 Error("CreateJDL()", "Define some input files for your analysis.");
959 // Compose list of input files
960 // Check if output files were defined
961 if (!fOutputFiles.Length()) {
962 Error("CreateJDL", "You must define at least one output file");
965 // Check if an output directory was defined and valid
966 if (!fGridOutputDir.Length()) {
967 Error("CreateJDL", "You must define AliEn output directory");
970 if (!fProductionMode) {
971 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
972 if (!DirectoryExists(fGridOutputDir)) {
973 if (gGrid->Mkdir(fGridOutputDir,"-p")) {
974 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
976 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
983 // Exit if any error up to now
984 if (error) return kFALSE;
986 if (!fUser.IsNull()) {
987 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
988 fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
990 fGridJDL->SetExecutable(fExecutable, "This is the startup script");
991 TString mergeExec = fExecutable;
992 mergeExec.ReplaceAll(".sh", "_merge.sh");
993 fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
994 mergeExec.ReplaceAll(".sh", ".C");
995 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
996 if (!fArguments.IsNull())
997 fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
998 if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
999 else fMergingJDL->SetArguments("wn.xml $2 $3"); // xml, stage, laststage(0 or 1)
1001 fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1002 fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1003 fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1004 fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1006 if (fMaxInitFailed > 0) {
1007 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1008 fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1010 if (fSplitMaxInputFileNumber > 0) {
1011 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1012 fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1014 if (!IsOneStageMerging()) {
1015 fMergingJDL->SetValue("SplitMaxInputFileNumber", "\"$3\"");
1016 fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1018 if (fSplitMode.Length()) {
1019 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1020 fGridJDL->SetDescription("Split", "We split per SE or file");
1022 fMergingJDL->SetValue("Split", "\"se\"");
1023 fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1024 if (!fAliROOTVersion.IsNull()) {
1025 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1026 fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1028 if (!fROOTVersion.IsNull()) {
1029 fGridJDL->AddToPackages("ROOT", fROOTVersion);
1030 fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1032 if (!fAPIVersion.IsNull()) {
1033 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1034 fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1036 if (!fExternalPackages.IsNull()) {
1037 arr = fExternalPackages.Tokenize(" ");
1039 while ((os=(TObjString*)next())) {
1040 TString pkgname = os->GetString();
1041 Int_t index = pkgname.Index("::");
1042 TString pkgversion = pkgname(index+2, pkgname.Length());
1043 pkgname.Remove(index);
1044 fGridJDL->AddToPackages(pkgname, pkgversion);
1045 fMergingJDL->AddToPackages(pkgname, pkgversion);
1049 fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1050 fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1051 fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1052 fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1053 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1054 TString analysisFile = fExecutable;
1055 analysisFile.ReplaceAll(".sh", ".root");
1056 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1057 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1058 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
1059 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
1060 if (fAdditionalLibs.Length()) {
1061 arr = fAdditionalLibs.Tokenize(" ");
1063 while ((os=(TObjString*)next())) {
1064 if (os->GetString().Contains(".so")) continue;
1065 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1066 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1071 TIter next(fPackages);
1073 while ((obj=next())) {
1074 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1075 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1078 if (fOutputArchive.Length()) {
1079 arr = fOutputArchive.Tokenize(" ");
1081 Bool_t first = kTRUE;
1082 const char *comment = "Files to be archived";
1083 const char *comment1 = comment;
1084 while ((os=(TObjString*)next())) {
1085 if (!first) comment = NULL;
1086 if (!os->GetString().Contains("@") && fCloseSE.Length())
1087 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1089 fGridJDL->AddToOutputArchive(os->GetString(), comment);
1093 // Output archive for the merging jdl
1094 TString outputArchive;
1095 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1096 outputArchive = "log_archive.zip:std*,*.stat@disk=1 ";
1097 // Add normal output files, extra files + terminate files
1098 TString files = GetListOfFiles("outextter");
1099 // Do not register merge excludes
1100 if (!fMergeExcludes.IsNull()) {
1101 arr = fMergeExcludes.Tokenize(" ");
1103 while ((os=(TObjString*)next1())) {
1104 files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1105 files.ReplaceAll(os->GetString(),"");
1109 files.ReplaceAll(".root", "*.root");
1110 outputArchive += Form("root_archive.zip:%s@disk=%d",files.Data(),fNreplicas);
1112 TString files = fOutputArchive;
1113 files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1114 outputArchive = files;
1116 arr = outputArchive.Tokenize(" ");
1120 while ((os=(TObjString*)next2())) {
1121 if (!first) comment = NULL;
1122 TString currentfile = os->GetString();
1123 if (!currentfile.Contains("@") && fCloseSE.Length())
1124 fMergingJDL->AddToOutputArchive(Form("%s@%s",currentfile.Data(), fCloseSE.Data()), comment);
1126 fMergingJDL->AddToOutputArchive(currentfile, comment);
1131 arr = fOutputFiles.Tokenize(",");
1133 Bool_t first = kTRUE;
1134 const char *comment = "Files to be saved";
1135 while ((os=(TObjString*)next())) {
1136 // Ignore ouputs in jdl that are also in outputarchive
1137 TString sout = os->GetString();
1138 sout.ReplaceAll("*", "");
1139 sout.ReplaceAll(".root", "");
1140 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1141 if (fOutputArchive.Contains(sout)) continue;
1142 if (!first) comment = NULL;
1143 if (!os->GetString().Contains("@") && fCloseSE.Length())
1144 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1146 fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1148 if (fMergeExcludes.Contains(sout)) continue;
1149 if (!os->GetString().Contains("@") && fCloseSE.Length())
1150 fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
1152 fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1155 fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1156 fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1157 TString validationScript = fValidationScript;
1158 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1159 validationScript.ReplaceAll(".sh", "_merge.sh");
1160 fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1161 if (fMasterResubmitThreshold) {
1162 fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1163 fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1165 // Write a jdl with 2 input parameters: collection name and output dir name.
1168 // Copy jdl to grid workspace
1170 // Check if an output directory was defined and valid
1171 if (!fGridOutputDir.Length()) {
1172 Error("CreateJDL", "You must define AliEn output directory");
1175 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1176 if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1177 if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1178 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
1180 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1186 if (TestBit(AliAnalysisGrid::kSubmit)) {
1187 TString mergeJDLName = fExecutable;
1188 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1189 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1190 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1191 if (fProductionMode) {
1192 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1193 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1195 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1196 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1197 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1198 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1200 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1201 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1204 if (fAdditionalLibs.Length()) {
1205 arr = fAdditionalLibs.Tokenize(" ");
1208 while ((os=(TObjString*)next())) {
1209 if (os->GetString().Contains(".so")) continue;
1210 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1211 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1212 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1217 TIter next(fPackages);
1219 while ((obj=next())) {
1220 if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1221 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
1222 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1229 //______________________________________________________________________________
1230 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1232 // Writes one or more JDL's corresponding to findex. If findex is negative,
1233 // all run numbers are considered in one go (jdl). For non-negative indices
1234 // they correspond to the indices in the array fInputFiles.
1235 if (!fInputFiles) return kFALSE;
1238 if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1239 workdir += fGridWorkingDir;
1240 fMergingJDL->AddToInputDataCollection("LF:$1/Stage_$2.xml,nodownload", "Collection of files to be merged for stage $2");
1241 fMergingJDL->SetOutputDirectory("$1/Stage_$2/#alien_counter_03i#", "Output directory");
1243 if (fProductionMode) {
1244 TIter next(fInputFiles);
1245 while ((os=next())) {
1246 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1248 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1250 if (!fRunNumbers.Length() && !fRunRange[0]) {
1251 // One jdl with no parameters in case input data is specified by name.
1252 TIter next(fInputFiles);
1254 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1255 if (!fOutputSingle.IsNull())
1256 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1258 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1259 fMergingJDL->SetOutputDirectory(fGridOutputDir);
1262 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1263 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1264 if (!fOutputSingle.IsNull()) {
1265 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1266 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1268 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1273 // Generate the JDL as a string
1274 TString sjdl = fGridJDL->Generate();
1275 TString sjdl1 = fMergingJDL->Generate();
1276 fMergingJDL->SetOutputDirectory("$1", "Output directory");
1277 fMergingJDL->AddToInputSandbox("LF:$1/$4");
1278 TString sjdl2 = fMergingJDL->Generate();
1279 Int_t index, index1;
1280 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1281 sjdl.ReplaceAll("(member", "\n (member");
1282 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1283 sjdl.ReplaceAll("{", "{\n ");
1284 sjdl.ReplaceAll("};", "\n};");
1285 sjdl.ReplaceAll("{\n \n", "{\n");
1286 sjdl.ReplaceAll("\n\n", "\n");
1287 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1288 sjdl1.ReplaceAll("\"LF:", "\n \"LF:");
1289 sjdl1.ReplaceAll("(member", "\n (member");
1290 sjdl1.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1291 sjdl1.ReplaceAll("{", "{\n ");
1292 sjdl1.ReplaceAll("};", "\n};");
1293 sjdl1.ReplaceAll("{\n \n", "{\n");
1294 sjdl1.ReplaceAll("\n\n", "\n");
1295 sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1296 sjdl2.ReplaceAll("\"LF:", "\n \"LF:");
1297 sjdl2.ReplaceAll("(member", "\n (member");
1298 sjdl2.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1299 sjdl2.ReplaceAll("{", "{\n ");
1300 sjdl2.ReplaceAll("};", "\n};");
1301 sjdl2.ReplaceAll("{\n \n", "{\n");
1302 sjdl2.ReplaceAll("\n\n", "\n");
1303 sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
1304 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1305 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
1306 index = sjdl.Index("JDLVariables");
1307 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1308 sjdl += "Workdirectorysize = {\"5000MB\"};";
1309 sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1310 sjdl1 += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1311 index = fJobTag.Index(":");
1312 if (index < 0) index = fJobTag.Length();
1313 TString jobTag = fJobTag;
1314 sjdl1.Prepend(Form("Jobtag = {\n \"comment:%s_Merging\"\n};\n", jobTag.Data()));
1315 sjdl1.Prepend("# Generated merging jdl \
1316 \n# $1 = full alien path to output directory to be merged \
1317 \n# $2 = merging stage \
1318 \n# $3 = maximum number of files to merge (must be >= 10000 for the last stage) \
1319 \n# $4 = xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1320 sjdl2.Prepend(Form("Jobtag = {\n \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
1321 sjdl2.Prepend("# Generated merging jdl \
1322 \n# $1 = full alien path to output directory to be merged \
1323 \n# $2 = merging stage \
1324 \n# $3 = maximum number of files to merge (must be >= 10000 for the last stage) \
1325 \n# $4 = xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1326 index = sjdl1.Index("JDLVariables");
1327 if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1328 index = sjdl2.Index("JDLVariables");
1329 if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
1330 sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1331 sjdl2 += "Workdirectorysize = {\"5000MB\"};";
1332 index = sjdl2.Index("Split =");
1334 index1 = sjdl2.Index("\n", index);
1335 sjdl2.Remove(index, index1-index+1);
1337 index = sjdl2.Index("SplitMaxInputFileNumber");
1339 index1 = sjdl2.Index("\n", index);
1340 sjdl2.Remove(index, index1-index+1);
1342 index = sjdl2.Index("InputDataCollection");
1344 index1 = sjdl2.Index(";", index);
1345 sjdl2.Remove(index, index1-index+1);
1347 index = sjdl2.Index("InputDataListFormat");
1349 index1 = sjdl2.Index("\n", index);
1350 sjdl2.Remove(index, index1-index+1);
1352 index = sjdl2.Index("InputDataList");
1354 index1 = sjdl2.Index("\n", index);
1355 sjdl2.Remove(index, index1-index+1);
1357 sjdl2.ReplaceAll("wn.xml", "$4");
1358 // Write jdl to file
1360 out.open(fJDLName.Data(), ios::out);
1362 Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
1365 out << sjdl << endl;
1367 TString mergeJDLName = fExecutable;
1368 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1371 out1.open(mergeJDLName.Data(), ios::out);
1373 Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
1376 out1 << sjdl1 << endl;
1379 TString finalJDL = mergeJDLName;
1380 finalJDL.ReplaceAll(".jdl", "_final.jdl");
1381 out2.open(finalJDL.Data(), ios::out);
1383 Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
1386 out2 << sjdl2 << endl;
1390 // Copy jdl to grid workspace
1392 Info("WriteJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1394 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1395 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1396 TString finalJDL = mergeJDLName;
1397 finalJDL.ReplaceAll(".jdl", "_final.jdl");
1398 TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
1399 if (fProductionMode) {
1400 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1401 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1402 locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
1404 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1405 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1406 if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
1407 Info("WriteJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1408 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1410 Info("WriteJDL", "\n##### Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
1411 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1412 TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
1418 //______________________________________________________________________________
1419 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1421 // Returns true if file exists.
1422 if (!gGrid) return kFALSE;
1424 slfn.ReplaceAll("alien://","");
1425 TGridResult *res = gGrid->Ls(slfn);
1426 if (!res) return kFALSE;
1427 TMap *map = dynamic_cast<TMap*>(res->At(0));
1432 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1433 if (!objs || !objs->GetString().Length()) {
1441 //______________________________________________________________________________
1442 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1444 // Returns true if directory exists. Can be also a path.
1445 if (!gGrid) return kFALSE;
1446 // Check if dirname is a path
1447 TString dirstripped = dirname;
1448 dirstripped = dirstripped.Strip();
1449 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1450 TString dir = gSystem->BaseName(dirstripped);
1452 TString path = gSystem->DirName(dirstripped);
1453 TGridResult *res = gGrid->Ls(path, "-F");
1454 if (!res) return kFALSE;
1458 while ((map=dynamic_cast<TMap*>(next()))) {
1459 obj = map->GetValue("name");
1461 if (dir == obj->GetName()) {
1470 //______________________________________________________________________________
1471 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
1473 // Check input data type.
1474 isCollection = kFALSE;
1478 Error("CheckDataType", "No connection to grid");
1481 isCollection = IsCollection(lfn);
1482 TString msg = "\n##### file: ";
1485 msg += " type: raw_collection;";
1486 // special treatment for collections
1488 // check for tag files in the collection
1489 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1491 msg += " using_tags: No (unknown)";
1492 Info("CheckDataType", "%s", msg.Data());
1495 const char* typeStr = res->GetKey(0, "origLFN");
1496 if (!typeStr || !strlen(typeStr)) {
1497 msg += " using_tags: No (unknown)";
1498 Info("CheckDataType", "%s", msg.Data());
1501 TString file = typeStr;
1502 useTags = file.Contains(".tag");
1503 if (useTags) msg += " using_tags: Yes";
1504 else msg += " using_tags: No";
1505 Info("CheckDataType", "%s", msg.Data());
1510 isXml = slfn.Contains(".xml");
1512 // Open xml collection and check if there are tag files inside
1513 msg += " type: xml_collection;";
1514 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1516 msg += " using_tags: No (unknown)";
1517 Info("CheckDataType", "%s", msg.Data());
1520 TMap *map = coll->Next();
1522 msg += " using_tags: No (unknown)";
1523 Info("CheckDataType", "%s", msg.Data());
1526 map = (TMap*)map->GetValue("");
1528 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1529 useTags = file.Contains(".tag");
1531 if (useTags) msg += " using_tags: Yes";
1532 else msg += " using_tags: No";
1533 Info("CheckDataType", "%s", msg.Data());
1536 useTags = slfn.Contains(".tag");
1537 if (slfn.Contains(".root")) msg += " type: root file;";
1538 else msg += " type: unknown file;";
1539 if (useTags) msg += " using_tags: Yes";
1540 else msg += " using_tags: No";
1541 Info("CheckDataType", "%s", msg.Data());
1544 //______________________________________________________________________________
1545 void AliAnalysisAlien::EnablePackage(const char *package)
1547 // Enables a par file supposed to exist in the current directory.
1548 TString pkg(package);
1549 pkg.ReplaceAll(".par", "");
1551 if (gSystem->AccessPathName(pkg)) {
1552 Fatal("EnablePackage", "Package %s not found", pkg.Data());
1555 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1556 Info("EnablePackage", "AliEn plugin will use .par packages");
1557 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1559 fPackages = new TObjArray();
1560 fPackages->SetOwner();
1562 fPackages->Add(new TObjString(pkg));
1565 //______________________________________________________________________________
1566 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
1568 // Make a tree from files having the location specified in fFileForTestMode.
1569 // Inspired from JF's CreateESDChain.
1570 if (fFileForTestMode.IsNull()) {
1571 Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
1574 if (gSystem->AccessPathName(fFileForTestMode)) {
1575 Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
1580 in.open(fFileForTestMode);
1582 // Read the input list of files and add them to the chain
1584 TChain *chain = new TChain(treeName);
1588 if (line.IsNull()) continue;
1589 if (count++ == fNtestFiles) break;
1590 TString esdFile(line);
1591 TFile *file = TFile::Open(esdFile);
1593 if (!file->IsZombie()) chain->Add(esdFile);
1596 Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
1600 if (!chain->GetListOfFiles()->GetEntries()) {
1601 Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
1609 //______________________________________________________________________________
1610 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1612 // Get job status for all jobs with jobid>jobidstart.
1613 static char mstatus[20];
1619 TGridJobStatusList *list = gGrid->Ps("");
1620 if (!list) return mstatus;
1621 Int_t nentries = list->GetSize();
1622 TGridJobStatus *status;
1624 for (Int_t ijob=0; ijob<nentries; ijob++) {
1625 status = (TGridJobStatus *)list->At(ijob);
1626 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1627 if (pid<jobidstart) continue;
1628 if (pid == lastid) {
1629 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1631 switch (status->GetStatus()) {
1632 case TGridJobStatus::kWAITING:
1634 case TGridJobStatus::kRUNNING:
1636 case TGridJobStatus::kABORTED:
1637 case TGridJobStatus::kFAIL:
1638 case TGridJobStatus::kUNKNOWN:
1640 case TGridJobStatus::kDONE:
1649 //______________________________________________________________________________
1650 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1652 // Returns true if file is a collection. Functionality duplicated from
1653 // TAlien::Type() because we don't want to directly depend on TAlien.
1655 Error("IsCollection", "No connection to grid");
1658 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1659 if (!res) return kFALSE;
1660 const char* typeStr = res->GetKey(0, "type");
1661 if (!typeStr || !strlen(typeStr)) return kFALSE;
1662 if (!strcmp(typeStr, "collection")) return kTRUE;
1667 //______________________________________________________________________________
1668 Bool_t AliAnalysisAlien::IsSingleOutput() const
1670 // Check if single-ouput option is on.
1671 return (!fOutputSingle.IsNull());
1674 //______________________________________________________________________________
1675 void AliAnalysisAlien::Print(Option_t *) const
1677 // Print current plugin settings.
1678 printf("### AliEn analysis plugin current settings ###\n");
1679 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1680 if (mgr && mgr->IsProofMode()) {
1681 TString proofType = "= PLUGIN IN PROOF MODE ON CLUSTER:_________________";
1682 if (TestBit(AliAnalysisGrid::kTest))
1683 proofType = "= PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
1684 printf("%s %s\n", proofType.Data(), fProofCluster.Data());
1685 if (!fProofDataSet.IsNull())
1686 printf("= Requested data set:___________________________ %s\n", fProofDataSet.Data());
1688 printf("= Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");
1690 printf("= Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");
1691 if (!fRootVersionForProof.IsNull())
1692 printf("= ROOT version requested________________________ %s\n", fRootVersionForProof.Data());
1694 printf("= ROOT version requested________________________ default\n");
1695 printf("= AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
1696 if (!fAliRootMode.IsNull())
1697 printf("= Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());
1699 printf("= Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
1700 if (fNproofWorkersPerSlave)
1701 printf("= Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
1702 if (TestSpecialBit(kClearPackages))
1703 printf("= ClearPackages requested...\n");
1704 if (fIncludePath.Data())
1705 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1706 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1707 if (fPackages && fPackages->GetEntries()) {
1708 TIter next(fPackages);
1711 while ((obj=next())) list += obj->GetName();
1712 printf("= Par files to be used: ________________________ %s\n", list.Data());
1714 if (TestSpecialBit(kProofConnectGrid))
1715 printf("= Requested PROOF connection to grid\n");
1718 printf("= OverwriteMode:________________________________ %d\n", fOverwriteMode);
1719 if (fOverwriteMode) {
1720 printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
1721 \n***** To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
1723 printf("= Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
1724 printf("= Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
1725 printf("= Production mode:______________________________ %d\n", fProductionMode);
1726 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1727 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1728 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1730 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1731 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1732 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1733 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1734 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1735 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1736 if (fRunNumbers.Length())
1737 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1739 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1740 if (!fRunRange[0] && !fRunNumbers.Length()) {
1741 TIter next(fInputFiles);
1744 while ((obj=next())) list += obj->GetName();
1745 printf("= Input files to be processed: _________________ %s\n", list.Data());
1747 if (TestBit(AliAnalysisGrid::kTest))
1748 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1749 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1750 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1751 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1752 printf("= List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
1753 printf("=====================================================================\n");
1754 printf("= Job price: ___________________________________ %d\n", fPrice);
1755 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1756 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1757 if (fMaxInitFailed>0)
1758 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1759 if (fMasterResubmitThreshold>0)
1760 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1761 printf("= Number of replicas for the output files_______ %d\n", fNreplicas);
1762 if (fNrunsPerMaster>0)
1763 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1764 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1765 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1766 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
1767 if (fArguments.Length())
1768 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1769 if (fExecutableArgs.Length())
1770 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1771 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1772 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1773 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1774 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1776 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1777 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1778 if (fIncludePath.Data())
1779 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1780 if (fCloseSE.Length())
1781 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1782 if (fFriendChainName.Length())
1783 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1784 if (fPackages && fPackages->GetEntries()) {
1785 TIter next(fPackages);
1788 while ((obj=next())) list += obj->GetName();
1789 printf("= Par files to be used: ________________________ %s\n", list.Data());
1793 //______________________________________________________________________________
1794 void AliAnalysisAlien::SetDefaults()
1796 // Set default values for everything. What cannot be filled will be left empty.
1797 if (fGridJDL) delete fGridJDL;
1798 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1799 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1802 fSplitMaxInputFileNumber = 100;
1804 fMasterResubmitThreshold = 0;
1809 fNrunsPerMaster = 1;
1810 fMaxMergeFiles = 100;
1812 fExecutable = "analysis.sh";
1813 fExecutableCommand = "root -b -q";
1815 fExecutableArgs = "";
1816 fAnalysisMacro = "myAnalysis.C";
1817 fAnalysisSource = "";
1818 fAdditionalLibs = "";
1822 fAliROOTVersion = "";
1823 fUser = ""; // Your alien user name
1824 fGridWorkingDir = "";
1825 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1826 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1827 fFriendChainName = "";
1828 fGridOutputDir = "output";
1829 fOutputArchive = "log_archive.zip:std*,*.stat@disk=1 root_archive.zip:*.root@disk=2";
1830 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1831 fInputFormat = "xml-single";
1832 fJDLName = "analysis.jdl";
1833 fJobTag = "Automatically generated analysis JDL";
1834 fMergeExcludes = "";
1837 SetCheckCopy(kTRUE);
1838 SetDefaultOutputs(kTRUE);
1842 //______________________________________________________________________________
1843 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
1845 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
1846 // First check if the result is already in the output directory.
1847 if (FileExists(Form("%s/%s",aliendir,filename))) {
1848 printf("Final merged results found. Not merging again.\n");
1851 // Now check the last stage done.
1854 if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
1857 // Next stage of merging
1859 TString pattern = "*root_archive.zip";
1860 if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
1861 TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
1862 if (res) delete res;
1863 // Write standard output to file
1864 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
1865 // Count the number of files inside
1867 ifile.open(Form("Stage_%d.xml",stage));
1868 if (!ifile.good()) {
1869 ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
1874 while (!ifile.eof()) {
1876 if (line.Contains("/event")) nfiles++;
1880 ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
1883 printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
1885 // Copy the file in the output directory
1886 printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
1887 TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
1888 // Check if this is the last stage to be done.
1889 Bool_t laststage = (nfiles<nperchunk);
1890 if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
1892 printf("### Submiting final merging stage %d\n", stage);
1893 TString finalJDL = jdl;
1894 finalJDL.ReplaceAll(".jdl", "_final.jdl");
1895 TString query = Form("submit %s %s %d 10000 Stage_%d.xml", finalJDL.Data(), aliendir, stage, stage);
1896 Int_t jobId = SubmitSingleJob(query);
1897 if (!jobId) return kFALSE;
1899 printf("### Submiting merging stage %d\n", stage);
1900 TString query = Form("submit %s %s %d %d wn.xml", jdl, aliendir, stage, nperchunk);
1901 Int_t jobId = SubmitSingleJob(query);
1902 if (!jobId) return kFALSE;
1907 //______________________________________________________________________________
1908 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
1910 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
1911 if (!gGrid) return 0;
1912 printf("=> %s ------> ",query);
1913 TGridResult *res = gGrid->Command(query);
1915 TString jobId = res->GetKey(0,"jobId");
1917 if (jobId.IsNull()) {
1918 printf("submission failed. Reason:\n");
1921 ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
1924 printf(" Job id: %s\n", jobId.Data());
1928 //______________________________________________________________________________
1929 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
1931 // Merge given output files from basedir. Basedir can be an alien output directory
1932 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
1933 // files in a group (ignored for xml input). Merging can be done in stages:
1934 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
1935 // stage=1 : works with an xml of all root_archive.zip in the output directory
1936 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
1937 TString outputFile = output;
1939 TString outputChunk;
1940 TString previousChunk = "";
1941 TObjArray *listoffiles = new TObjArray();
1942 // listoffiles->SetOwner();
1943 Int_t countChunk = 0;
1944 Int_t countZero = nmaxmerge;
1945 Bool_t merged = kTRUE;
1946 Int_t index = outputFile.Index("@");
1947 if (index > 0) outputFile.Remove(index);
1948 TString inputFile = outputFile;
1949 TString sbasedir = basedir;
1950 if (sbasedir.Contains(".xml")) {
1951 // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
1952 nmaxmerge = 9999999;
1953 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
1955 ::Error("MergeOutput", "Input XML collection empty.");
1958 // Iterate grid collection
1959 while (coll->Next()) {
1960 TString fname = gSystem->DirName(coll->GetTURL());
1963 listoffiles->Add(new TNamed(fname.Data(),""));
1966 command = Form("find %s/ *%s", basedir, inputFile.Data());
1967 printf("command: %s\n", command.Data());
1968 TGridResult *res = gGrid->Command(command);
1970 ::Error("MergeOutput","No result for the find command\n");
1976 while ((map=(TMap*)nextmap())) {
1977 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1978 if (!objs || !objs->GetString().Length()) {
1979 // Nothing found - skip this output
1984 listoffiles->Add(new TNamed(objs->GetName(),""));
1988 if (!listoffiles->GetEntries()) {
1989 ::Error("MergeOutput","No result for the find command\n");
1994 TFileMerger *fm = 0;
1995 TIter next0(listoffiles);
1996 TObjArray *listoffilestmp = new TObjArray();
1997 listoffilestmp->SetOwner();
2000 // Keep only the files at upper level
2001 Int_t countChar = 0;
2002 while ((nextfile=next0())) {
2003 snextfile = nextfile->GetName();
2004 Int_t crtCount = snextfile.CountChar('/');
2005 if (nextfile == listoffiles->First()) countChar = crtCount;
2006 if (crtCount < countChar) countChar = crtCount;
2009 while ((nextfile=next0())) {
2010 snextfile = nextfile->GetName();
2011 Int_t crtCount = snextfile.CountChar('/');
2012 if (crtCount > countChar) {
2016 listoffilestmp->Add(nextfile);
2019 listoffiles = listoffilestmp; // Now contains 'good' files
2020 listoffiles->Print();
2021 TIter next(listoffiles);
2022 // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2023 outputChunk = outputFile;
2024 outputChunk.ReplaceAll(".root", "_*.root");
2025 // Check for existent temporary merge files
2026 // Check overwrite mode and remove previous partial results if needed
2027 // Preserve old merging functionality for stage 0.
2029 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2031 // Skip as many input files as in a chunk
2032 for (Int_t counter=0; counter<nmaxmerge; counter++) {
2035 ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
2039 snextfile = nextfile->GetName();
2041 outputChunk = outputFile;
2042 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2044 if (gSystem->AccessPathName(outputChunk)) continue;
2045 // Merged file with chunks up to <countChunk> found
2046 ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
2047 previousChunk = outputChunk;
2051 countZero = nmaxmerge;
2053 while ((nextfile=next())) {
2054 snextfile = nextfile->GetName();
2055 // Loop 'find' results and get next LFN
2056 if (countZero == nmaxmerge) {
2057 // First file in chunk - create file merger and add previous chunk if any.
2058 fm = new TFileMerger(kFALSE);
2059 fm->SetFastMethod(kTRUE);
2060 if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
2061 outputChunk = outputFile;
2062 outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2064 // If last file found, put merged results in the output file
2065 if (nextfile == listoffiles->Last()) outputChunk = outputFile;
2066 // Add file to be merged and decrement chunk counter.
2067 fm->AddFile(snextfile);
2069 if (countZero==0 || nextfile == listoffiles->Last()) {
2070 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2071 // Nothing found - skip this output
2072 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2076 fm->OutputFile(outputChunk);
2077 // Merge the outputs, then go to next chunk
2079 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2083 ::Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
2084 gSystem->Unlink(previousChunk);
2086 if (nextfile == listoffiles->Last()) break;
2088 countZero = nmaxmerge;
2089 previousChunk = outputChunk;
2096 // Merging stage different than 0.
2097 // Move to the begining of the requested chunk.
2098 fm = new TFileMerger(kFALSE);
2099 fm->SetFastMethod(kTRUE);
2100 while ((nextfile=next())) fm->AddFile(nextfile->GetName());
2102 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2103 // Nothing found - skip this output
2104 ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2108 fm->OutputFile(outputFile);
2109 // Merge the outputs
2111 ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2115 ::Info("MergeOutput", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
2121 //______________________________________________________________________________
2122 Bool_t AliAnalysisAlien::MergeOutputs()
2124 // Merge analysis outputs existing in the AliEn space.
2125 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
2126 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2128 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
2132 if (!TestBit(AliAnalysisGrid::kMerge)) {
2133 Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
2136 if (fProductionMode) {
2137 Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
2140 Info("MergeOutputs", "Submitting merging JDL");
2141 if (!SubmitMerging()) return kFALSE;
2142 Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
2143 Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
2146 // Get the output path
2147 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2148 if (!DirectoryExists(fGridOutputDir)) {
2149 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
2152 if (!fOutputFiles.Length()) {
2153 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2156 // Check if fast read option was requested
2157 Info("MergeOutputs", "Started local merging of output files from: alien://%s \
2158 \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
2159 if (fFastReadOption) {
2160 Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
2161 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2162 gEnv->SetValue("XNet.ConnectTimeout",50);
2163 gEnv->SetValue("XNet.RequestTimeout",50);
2164 gEnv->SetValue("XNet.MaxRedirectCount",2);
2165 gEnv->SetValue("XNet.ReconnectTimeout",50);
2166 gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
2168 // Make sure we change the temporary directory
2169 gSystem->Setenv("TMPDIR", gSystem->pwd());
2170 TObjArray *list = fOutputFiles.Tokenize(",");
2174 Bool_t merged = kTRUE;
2175 while((str=(TObjString*)next())) {
2176 outputFile = str->GetString();
2177 Int_t index = outputFile.Index("@");
2178 if (index > 0) outputFile.Remove(index);
2179 TString outputChunk = outputFile;
2180 outputChunk.ReplaceAll(".root", "_*.root");
2181 // Skip already merged outputs
2182 if (!gSystem->AccessPathName(outputFile)) {
2183 if (fOverwriteMode) {
2184 Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
2185 gSystem->Unlink(outputFile);
2186 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2187 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2188 outputChunk.Data());
2189 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2192 Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
2196 if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2197 Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2198 outputChunk.Data());
2199 gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2202 if (fMergeExcludes.Length() &&
2203 fMergeExcludes.Contains(outputFile.Data())) continue;
2204 // Perform a 'find' command in the output directory, looking for registered outputs
2205 merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
2207 Error("MergeOutputs", "Terminate() will NOT be executed");
2210 TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2211 if (fileOpened) fileOpened->Close();
2216 //______________________________________________________________________________
2217 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2219 // Use the output files connected to output containers from the analysis manager
2220 // rather than the files defined by SetOutputFiles
2221 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
2222 Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
2223 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2226 //______________________________________________________________________________
2227 void AliAnalysisAlien::SetOutputFiles(const char *list)
2229 // Manually set the output files list.
2230 // Removes duplicates. Not allowed if default outputs are not disabled.
2231 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2232 Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2235 Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2237 TString slist = list;
2238 if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2239 TObjArray *arr = slist.Tokenize(" ");
2243 while ((os=(TObjString*)next())) {
2244 sout = os->GetString();
2245 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2246 if (fOutputFiles.Contains(sout)) continue;
2247 if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2248 fOutputFiles += sout;
2253 //______________________________________________________________________________
2254 void AliAnalysisAlien::SetOutputArchive(const char *list)
2256 // Manually set the output archive list. Free text - you are on your own...
2257 // Not allowed if default outputs are not disabled.
2258 if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2259 Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2262 Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2263 fOutputArchive = list;
2266 //______________________________________________________________________________
2267 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2269 // Setting a prefered output SE is not allowed anymore.
2270 Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2273 //______________________________________________________________________________
2274 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
2276 // Start remote grid analysis.
2277 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2278 Bool_t testMode = TestBit(AliAnalysisGrid::kTest);
2279 if (!mgr || !mgr->IsInitialized()) {
2280 Error("StartAnalysis", "You need an initialized analysis manager for this");
2283 // Are we in PROOF mode ?
2284 if (mgr->IsProofMode()) {
2285 Info("StartAnalysis", "##### Starting PROOF analysis on cluster <%s> via the plugin #####", fProofCluster.Data());
2286 if (fProofCluster.IsNull()) {
2287 Error("StartAnalysis", "You need to specify the proof cluster name via SetProofCluster");
2290 if (fProofDataSet.IsNull() && !testMode) {
2291 Error("StartAnalysis", "You need to specify a dataset using SetProofDataSet()");
2294 // Set the needed environment
2295 gEnv->SetValue("XSec.GSI.DelegProxy","2");
2296 // Do we need to reset PROOF ? The success of the Reset operation cannot be checked
2297 if (fProofReset && !testMode) {
2298 if (fProofReset==1) {
2299 Info("StartAnalysis", "Sending soft reset signal to proof cluster %s", fProofCluster.Data());
2300 gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kFALSE);", fProofCluster.Data()));
2302 Info("StartAnalysis", "Sending hard reset signal to proof cluster %s", fProofCluster.Data());
2303 gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kTRUE);", fProofCluster.Data()));
2305 Info("StartAnalysis", "Stopping the analysis. Please use SetProofReset(0) to resume.");
2308 // Do we need to change the ROOT version ? The success of this cannot be checked.
2309 if (!fRootVersionForProof.IsNull() && !testMode) {
2310 gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"%s\");",
2311 fProofCluster.Data(), fRootVersionForProof.Data()));
2313 // Connect to PROOF and check the status
2316 if (fNproofWorkersPerSlave) sworkers = Form("workers=%dx", fNproofWorkersPerSlave);
2317 else if (fNproofWorkers) sworkers = Form("workers=%d", fNproofWorkers);
2319 if (!sworkers.IsNull())
2320 proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"%s\");", fProofCluster.Data(), sworkers.Data()));
2322 proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
2324 proof = gROOT->ProcessLine("TProof::Open(\"\");");
2326 Error("StartAnalysis", "Could not start PROOF in test mode");
2331 Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
2334 if (fNproofWorkersPerSlave*fNproofWorkers > 0)
2335 gROOT->ProcessLine(Form("gProof->SetParallel(%d);", fNproofWorkers));
2336 // Is dataset existing ?
2338 TString dataset = fProofDataSet;
2339 Int_t index = dataset.Index("#");
2340 if (index>=0) dataset.Remove(index);
2341 // if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
2342 // Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
2345 // Info("StartAnalysis", "Dataset %s found", dataset.Data());
2347 // Is ClearPackages() needed ?
2348 if (TestSpecialBit(kClearPackages)) {
2349 Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
2350 gROOT->ProcessLine("gProof->ClearPackages();");
2352 // Is a given aliroot mode requested ?
2355 if (!fAliRootMode.IsNull()) {
2356 TString alirootMode = fAliRootMode;
2357 if (alirootMode == "default") alirootMode = "";
2358 Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
2359 optionsList.SetOwner();
2360 optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
2361 // Check the additional libs to be loaded
2363 Bool_t parMode = kFALSE;
2364 if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:ANALYSISalice";
2365 // Parse the extra libs for .so
2366 if (fAdditionalLibs.Length()) {
2367 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2370 while((str=(TObjString*)next())) {
2371 if (str->GetString().Contains(".so")) {
2373 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());
2376 TString stmp = str->GetName();
2377 if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
2378 stmp.ReplaceAll(".so","");
2379 if (!extraLibs.IsNull()) extraLibs += ":";
2383 if (str->GetString().Contains(".par")) {
2384 // The first par file found in the list will not allow any further .so
2386 if (!parLibs.IsNull()) parLibs += ":";
2387 parLibs += str->GetName();
2391 if (list) delete list;
2393 if (!extraLibs.IsNull()) optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
2394 // Check extra includes
2395 if (!fIncludePath.IsNull()) {
2396 TString includePath = fIncludePath;
2397 includePath.ReplaceAll(" ",":");
2398 includePath.Strip(TString::kTrailing, ':');
2399 Info("StartAnalysis", "Adding extra includes: %s",includePath.Data());
2400 optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
2402 // Check if connection to grid is requested
2403 if (TestSpecialBit(kProofConnectGrid))
2404 optionsList.Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
2405 // Enable AliRoot par
2407 // Enable proof lite package
2408 TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
2409 for (Int_t i=0; i<optionsList.GetSize(); i++) {
2410 TNamed *obj = (TNamed*)optionsList.At(i);
2411 printf("%s %s\n", obj->GetName(), obj->GetTitle());
2413 if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
2414 && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)0x%lx);",alirootLite.Data(),(ULong_t)&optionsList))) {
2415 Info("StartAnalysis", "AliRootProofLite enabled");
2417 Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
2421 if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)0x%lx);",
2422 fAliROOTVersion.Data(), (ULong_t)&optionsList))) {
2423 Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
2427 // Enable first par files from fAdditionalLibs
2428 if (!parLibs.IsNull()) {
2429 TObjArray *list = parLibs.Tokenize(":");
2431 TObjString *package;
2432 while((package=(TObjString*)next())) {
2433 TString spkg = package->GetName();
2434 spkg.ReplaceAll(".par", "");
2435 gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2436 if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2437 TString enablePackage = (testMode)?Form("gProof->EnablePackage(\"%s\",kFALSE);", package->GetName()):Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName());
2438 if (gROOT->ProcessLine(enablePackage)) {
2439 Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2443 Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2447 if (list) delete list;
2450 if (fAdditionalLibs.Contains(".so") && !testMode) {
2451 Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
2452 \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
2456 // Enable par files if requested
2457 if (fPackages && fPackages->GetEntries()) {
2458 TIter next(fPackages);
2460 while ((package=next())) {
2461 // Skip packages already enabled
2462 if (parLibs.Contains(package->GetName())) continue;
2463 TString spkg = package->GetName();
2464 spkg.ReplaceAll(".par", "");
2465 gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
2466 if (gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
2467 if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName()))) {
2468 Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
2472 Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
2477 // Do we need to load analysis source files ?
2478 // NOTE: don't load on client since this is anyway done by the user to attach his task.
2479 if (fAnalysisSource.Length()) {
2480 TObjArray *list = fAnalysisSource.Tokenize(" ");
2483 while((str=(TObjString*)next())) {
2484 gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
2486 if (list) delete list;
2489 // Register dataset to proof lite.
2490 if (fFileForTestMode.IsNull()) {
2491 Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2494 if (gSystem->AccessPathName(fFileForTestMode)) {
2495 Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2498 TFileCollection *coll = new TFileCollection();
2499 coll->AddFromFile(fFileForTestMode);
2500 gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)0x%lx, \"OV\");", (ULong_t)coll));
2501 gROOT->ProcessLine("gProof->ShowDataSets()");
2506 // Check if output files have to be taken from the analysis manager
2507 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2508 // Add output files and AOD files
2509 fOutputFiles = GetListOfFiles("outaod");
2510 // Add extra files registered to the analysis manager
2511 TString extra = GetListOfFiles("ext");
2512 if (!extra.IsNull()) {
2513 extra.ReplaceAll(".root", "*.root");
2514 if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2515 fOutputFiles += extra;
2517 // Compose the output archive.
2518 fOutputArchive = "log_archive.zip:std*,*.stat@disk=1 ";
2519 fOutputArchive += Form("root_archive.zip:%s@disk=%d",fOutputFiles.Data(),fNreplicas);
2521 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
2522 if (TestBit(AliAnalysisGrid::kOffline)) {
2523 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
2524 \n there nor any job run. You can revise the JDL and analysis \
2525 \n macro then run the same in \"submit\" mode.");
2526 } else if (TestBit(AliAnalysisGrid::kTest)) {
2527 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
2529 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
2530 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
2531 \n space and job submitted.");
2532 } else if (TestBit(AliAnalysisGrid::kMerge)) {
2533 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
2534 if (fMergeViaJDL) CheckInputData();
2537 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
2542 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
2545 if (IsCheckCopy() && gGrid) CheckFileCopy(gGrid->GetHomeDirectory());
2546 if (!CheckInputData()) {
2547 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
2550 if (!CreateDataset(fDataPattern)) {
2552 if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
2553 if (fRunNumbers.Length()) serror = "run numbers";
2554 if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
2555 serror += Form("\n or data pattern <%s>", fDataPattern.Data());
2556 Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
2559 WriteAnalysisFile();
2560 WriteAnalysisMacro();
2562 WriteValidationScript();
2564 WriteMergingMacro();
2565 WriteMergeExecutable();
2566 WriteValidationScript(kTRUE);
2568 if (!CreateJDL()) return kFALSE;
2569 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2571 // Locally testing the analysis
2572 Info("StartAnalysis", "\n_______________________________________________________________________ \
2573 \n Running analysis script in a daughter shell as on a worker node \
2574 \n_______________________________________________________________________");
2575 TObjArray *list = fOutputFiles.Tokenize(",");
2579 while((str=(TObjString*)next())) {
2580 outputFile = str->GetString();
2581 Int_t index = outputFile.Index("@");
2582 if (index > 0) outputFile.Remove(index);
2583 if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
2586 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
2587 gSystem->Exec(Form("bash %s",fValidationScript.Data()));
2588 // gSystem->Exec("cat stdout");
2591 // Check if submitting is managed by LPM manager
2592 if (fProductionMode) {
2593 TString prodfile = fJDLName;
2594 prodfile.ReplaceAll(".jdl", ".prod");
2595 WriteProductionFile(prodfile);
2596 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
2599 // Submit AliEn job(s)
2600 gGrid->Cd(fGridOutputDir);
2603 if (!fRunNumbers.Length() && !fRunRange[0]) {
2604 // Submit a given xml or a set of runs
2605 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
2606 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
2608 const char *cjobId = res->GetKey(0,"jobId");
2612 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
2615 Info("StartAnalysis", "\n_______________________________________________________________________ \
2616 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2617 \n_______________________________________________________________________",
2618 fJDLName.Data(), cjobId);
2623 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2627 // Submit for a range of enumeration of runs.
2628 if (!Submit()) return kFALSE;
2631 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2632 \n You may exit at any time and terminate the job later using the option <terminate> \
2633 \n ##################################################################################", jobID.Data());
2634 gSystem->Exec("aliensh");
2638 //______________________________________________________________________________
2639 const char *AliAnalysisAlien::GetListOfFiles(const char *type)
2641 // Get a comma-separated list of output files of the requested type.
2642 // Type can be (case unsensitive):
2643 // aod - list of aod files (std, extensions and filters)
2644 // out - list of output files connected to containers (but not aod's or extras)
2645 // ext - list of extra files registered to the manager
2646 // ter - list of files produced in terminate
2647 static TString files;
2649 TString stype = type;
2651 TString aodfiles, extra;
2652 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2654 ::Error("GetListOfFiles", "Cannot call this without analysis manager");
2655 return files.Data();
2657 if (mgr->GetOutputEventHandler()) {
2658 aodfiles = mgr->GetOutputEventHandler()->GetOutputFileName();
2659 TString extraaod = mgr->GetOutputEventHandler()->GetExtraOutputs();
2660 if (!extraaod.IsNull()) {
2662 aodfiles += extraaod;
2665 if (stype.Contains("aod")) {
2667 if (stype == "aod") return files.Data();
2669 // Add output files that are not in the list of AOD files
2670 TString outputfiles = "";
2671 TIter next(mgr->GetOutputs());
2672 AliAnalysisDataContainer *output;
2673 const char *filename = 0;
2674 while ((output=(AliAnalysisDataContainer*)next())) {
2675 filename = output->GetFileName();
2676 if (!(strcmp(filename, "default"))) continue;
2677 if (outputfiles.Contains(filename)) continue;
2678 if (aodfiles.Contains(filename)) continue;
2679 if (!outputfiles.IsNull()) outputfiles += ",";
2680 outputfiles += filename;
2682 if (stype.Contains("out")) {
2683 if (!files.IsNull()) files += ",";
2684 files += outputfiles;
2685 if (stype == "out") return files.Data();
2687 // Add extra files registered to the analysis manager
2689 extra = mgr->GetExtraFiles();
2690 if (!extra.IsNull()) {
2692 extra.ReplaceAll(" ", ",");
2693 TObjArray *fextra = extra.Tokenize(",");
2694 TIter nextx(fextra);
2696 while ((obj=nextx())) {
2697 if (aodfiles.Contains(obj->GetName())) continue;
2698 if (outputfiles.Contains(obj->GetName())) continue;
2699 if (sextra.Contains(obj->GetName())) continue;
2700 if (!sextra.IsNull()) sextra += ",";
2701 sextra += obj->GetName();
2704 if (stype.Contains("ext")) {
2705 if (!files.IsNull()) files += ",";
2709 if (stype == "ext") return files.Data();
2711 if (!fTerminateFiles.IsNull()) {
2712 fTerminateFiles.Strip();
2713 fTerminateFiles.ReplaceAll(" ",",");
2714 TObjArray *fextra = fTerminateFiles.Tokenize(",");
2715 TIter nextx(fextra);
2717 while ((obj=nextx())) {
2718 if (aodfiles.Contains(obj->GetName())) continue;
2719 if (outputfiles.Contains(obj->GetName())) continue;
2720 if (termfiles.Contains(obj->GetName())) continue;
2721 if (sextra.Contains(obj->GetName())) continue;
2722 if (!termfiles.IsNull()) termfiles += ",";
2723 termfiles += obj->GetName();
2727 if (stype.Contains("ter")) {
2728 if (!files.IsNull() && !termfiles.IsNull()) {
2733 return files.Data();
2736 //______________________________________________________________________________
2737 Bool_t AliAnalysisAlien::Submit()
2739 // Submit all master jobs.
2740 Int_t nmasterjobs = fInputFiles->GetEntries();
2741 Long_t tshoot = gSystem->Now();
2742 if (!fNsubmitted && !SubmitNext()) return kFALSE;
2743 while (fNsubmitted < nmasterjobs) {
2744 Long_t now = gSystem->Now();
2745 if ((now-tshoot)>30000) {
2747 if (!SubmitNext()) return kFALSE;
2753 //______________________________________________________________________________
2754 Bool_t AliAnalysisAlien::SubmitMerging()
2756 // Submit all merging jobs.
2757 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2758 gGrid->Cd(fGridOutputDir);
2759 TString mergeJDLName = fExecutable;
2760 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2761 Int_t ntosubmit = fInputFiles->GetEntries();
2762 for (Int_t i=0; i<ntosubmit; i++) {
2763 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2764 runOutDir.ReplaceAll(".xml", "");
2765 if (fOutputToRunNo) {
2766 // The output directory is the run number
2767 printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
2768 runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
2770 // The output directory is the master number in 3 digits format
2771 printf("### Submitting merging job for master <%03d>\n", i);
2772 runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
2774 // Check now the number of merging stages.
2775 TObjArray *list = fOutputFiles.Tokenize(",");
2779 while((str=(TObjString*)next())) {
2780 outputFile = str->GetString();
2781 Int_t index = outputFile.Index("@");
2782 if (index > 0) outputFile.Remove(index);
2783 if (!fMergeExcludes.Contains(outputFile)) break;
2786 Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, mergeJDLName);
2787 if (!done) return kFALSE;
2789 if (!ntosubmit) return kTRUE;
2790 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
2791 \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
2792 \n ##################################################################################");
2793 gSystem->Exec("aliensh");
2797 //______________________________________________________________________________
2798 Bool_t AliAnalysisAlien::SubmitNext()
2800 // Submit next bunch of master jobs if the queue is free. The first master job is
2801 // submitted right away, while the next will not be unless the previous was split.
2802 // The plugin will not submit new master jobs if there are more that 500 jobs in
2804 static Bool_t iscalled = kFALSE;
2805 static Int_t firstmaster = 0;
2806 static Int_t lastmaster = 0;
2807 static Int_t npermaster = 0;
2808 if (iscalled) return kTRUE;
2810 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2811 Int_t ntosubmit = 0;
2814 Int_t nmasterjobs = fInputFiles->GetEntries();
2817 if (!IsUseSubmitPolicy()) {
2819 Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
2820 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
2821 ntosubmit = nmasterjobs;
2824 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
2825 printf("=== master %d: %s\n", lastmaster, status.Data());
2826 // If last master not split, just return
2827 if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
2828 // No more than 100 waiting jobs
2829 if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
2830 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
2831 if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
2832 if (!ntosubmit) ntosubmit = 1;
2833 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
2834 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2836 for (Int_t i=0; i<ntosubmit; i++) {
2837 // Submit for a range of enumeration of runs.
2838 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
2840 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2841 runOutDir.ReplaceAll(".xml", "");
2843 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2845 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
2846 printf("********* %s\n",query.Data());
2847 res = gGrid->Command(query);
2849 TString cjobId1 = res->GetKey(0,"jobId");
2850 if (!cjobId1.Length()) {
2854 Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2857 Info("StartAnalysis", "\n_______________________________________________________________________ \
2858 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2859 \n_______________________________________________________________________",
2860 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
2863 lastmaster = cjobId1.Atoi();
2864 if (!firstmaster) firstmaster = lastmaster;
2869 Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2877 //______________________________________________________________________________
2878 void AliAnalysisAlien::WriteAnalysisFile()
2880 // Write current analysis manager into the file <analysisFile>
2881 TString analysisFile = fExecutable;
2882 analysisFile.ReplaceAll(".sh", ".root");
2883 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2884 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2885 if (!mgr || !mgr->IsInitialized()) {
2886 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2889 // Check analysis type
2891 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
2892 handler = (TObject*)mgr->GetInputEventHandler();
2894 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
2895 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
2897 TDirectory *cdir = gDirectory;
2898 TFile *file = TFile::Open(analysisFile, "RECREATE");
2900 // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
2901 if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
2902 // Unless merging makes no sense
2903 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
2906 // Enable termination for local jobs
2907 mgr->SetSkipTerminate(kFALSE);
2909 if (cdir) cdir->cd();
2910 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
2912 Bool_t copy = kTRUE;
2913 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2916 TString workdir = gGrid->GetHomeDirectory();
2917 workdir += fGridWorkingDir;
2918 Info("WriteAnalysisFile", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
2919 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
2920 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
2924 //______________________________________________________________________________
2925 void AliAnalysisAlien::WriteAnalysisMacro()
2927 // Write the analysis macro that will steer the analysis in grid mode.
2928 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2930 out.open(fAnalysisMacro.Data(), ios::out);
2932 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2935 Bool_t hasSTEERBase = kFALSE;
2936 Bool_t hasESD = kFALSE;
2937 Bool_t hasAOD = kFALSE;
2938 Bool_t hasANALYSIS = kFALSE;
2939 Bool_t hasANALYSISalice = kFALSE;
2940 Bool_t hasCORRFW = kFALSE;
2941 TString func = fAnalysisMacro;
2942 TString type = "ESD";
2943 TString comment = "// Analysis using ";
2944 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2945 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2949 if (type!="AOD" && fFriendChainName!="") {
2950 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2953 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2954 else comment += " data";
2955 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2956 func.ReplaceAll(".C", "");
2957 out << "void " << func.Data() << "()" << endl;
2959 out << comment.Data() << endl;
2960 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2961 out << " TStopwatch timer;" << endl;
2962 out << " timer.Start();" << endl << endl;
2963 // Change temp directory to current one
2964 out << "// Set temporary merging directory to current one" << endl;
2965 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
2966 // Reset existing include path
2967 out << "// Reset existing include path and add current directory first in the search" << endl;
2968 out << " gSystem->SetIncludePath(\"-I.\");" << endl;
2969 if (!fExecutableCommand.Contains("aliroot")) {
2970 out << "// load base root libraries" << endl;
2971 out << " gSystem->Load(\"libTree\");" << endl;
2972 out << " gSystem->Load(\"libGeom\");" << endl;
2973 out << " gSystem->Load(\"libVMC\");" << endl;
2974 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
2975 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
2977 if (fAdditionalRootLibs.Length()) {
2978 // in principle libtree /lib geom libvmc etc. can go into this list, too
2979 out << "// Add aditional libraries" << endl;
2980 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2983 while((str=(TObjString*)next())) {
2984 if (str->GetString().Contains(".so"))
2985 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2987 if (list) delete list;
2989 out << "// Load analysis framework libraries" << endl;
2990 TString setupPar = "AliAnalysisAlien::SetupPar";
2992 if (!fExecutableCommand.Contains("aliroot")) {
2993 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2994 out << " gSystem->Load(\"libESD\");" << endl;
2995 out << " gSystem->Load(\"libAOD\");" << endl;
2997 out << " gSystem->Load(\"libANALYSIS\");" << endl;
2998 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2999 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3001 TIter next(fPackages);
3004 while ((obj=next())) {
3005 pkgname = obj->GetName();
3006 if (pkgname == "STEERBase" ||
3007 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3008 if (pkgname == "ESD" ||
3009 pkgname == "ESD.par") hasESD = kTRUE;
3010 if (pkgname == "AOD" ||
3011 pkgname == "AOD.par") hasAOD = kTRUE;
3012 if (pkgname == "ANALYSIS" ||
3013 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
3014 if (pkgname == "ANALYSISalice" ||
3015 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3016 if (pkgname == "CORRFW" ||
3017 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
3019 if (hasANALYSISalice) setupPar = "SetupPar";
3020 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
3021 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3022 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
3023 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
3024 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
3025 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
3026 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
3027 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3028 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3029 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3030 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3031 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3032 out << "// Compile other par packages" << endl;
3034 while ((obj=next())) {
3035 pkgname = obj->GetName();
3036 if (pkgname == "STEERBase" ||
3037 pkgname == "STEERBase.par" ||
3039 pkgname == "ESD.par" ||
3041 pkgname == "AOD.par" ||
3042 pkgname == "ANALYSIS" ||
3043 pkgname == "ANALYSIS.par" ||
3044 pkgname == "ANALYSISalice" ||
3045 pkgname == "ANALYSISalice.par" ||
3046 pkgname == "CORRFW" ||
3047 pkgname == "CORRFW.par") continue;
3048 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3051 out << "// include path" << endl;
3052 // Get the include path from the interpreter and remove entries pointing to AliRoot
3053 out << " TString intPath = gInterpreter->GetIncludePath();" << endl;
3054 out << " TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3055 out << " TIter nextpath(listpaths);" << endl;
3056 out << " TObjString *pname;" << endl;
3057 out << " while ((pname=(TObjString*)nextpath())) {" << endl;
3058 out << " TString current = pname->GetName();" << endl;
3059 out << " if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3060 out << " gSystem->AddIncludePath(current);" << endl;
3061 out << " }" << endl;
3062 out << " if (listpaths) delete listpaths;" << endl;
3063 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3064 out << " gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3065 out << " printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3066 if (fAdditionalLibs.Length()) {
3067 out << "// Add aditional AliRoot libraries" << endl;
3068 TObjArray *list = fAdditionalLibs.Tokenize(" ");
3071 while((str=(TObjString*)next())) {
3072 if (str->GetString().Contains(".so"))
3073 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3074 if (str->GetString().Contains(".par"))
3075 out << " if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
3077 if (list) delete list;
3080 out << "// analysis source to be compiled at runtime (if any)" << endl;
3081 if (fAnalysisSource.Length()) {
3082 TObjArray *list = fAnalysisSource.Tokenize(" ");
3085 while((str=(TObjString*)next())) {
3086 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3088 if (list) delete list;
3091 // out << " printf(\"Currently load libraries:\\n\");" << endl;
3092 // out << " printf(\"%s\\n\", gSystem->GetLibraries());" << endl;
3093 if (fFastReadOption) {
3094 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 !!! \
3095 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3096 out << "// fast xrootd reading enabled" << endl;
3097 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3098 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3099 out << " gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3100 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3101 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3102 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3104 out << "// connect to AliEn and make the chain" << endl;
3105 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
3106 out << "// read the analysis manager from file" << endl;
3107 TString analysisFile = fExecutable;
3108 analysisFile.ReplaceAll(".sh", ".root");
3109 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
3110 out << " if (!file) return;" << endl;
3111 out << " TIter nextkey(file->GetListOfKeys());" << endl;
3112 out << " AliAnalysisManager *mgr = 0;" << endl;
3113 out << " TKey *key;" << endl;
3114 out << " while ((key=(TKey*)nextkey())) {" << endl;
3115 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
3116 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
3117 out << " };" << endl;
3118 out << " if (!mgr) {" << endl;
3119 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file " << analysisFile <<"\");" << endl;
3120 out << " return;" << endl;
3121 out << " }" << endl << endl;
3122 out << " mgr->PrintStatus();" << endl;
3123 if (AliAnalysisManager::GetAnalysisManager()) {
3124 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3125 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3127 if (TestBit(AliAnalysisGrid::kTest))
3128 out << " AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3130 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3133 if (IsUsingTags()) {
3134 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
3136 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
3138 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
3139 out << " timer.Stop();" << endl;
3140 out << " timer.Print();" << endl;
3141 out << "}" << endl << endl;
3142 if (IsUsingTags()) {
3143 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
3145 out << "// Create a chain using tags from the xml file." << endl;
3146 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
3147 out << " if (!coll) {" << endl;
3148 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3149 out << " return NULL;" << endl;
3150 out << " }" << endl;
3151 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
3152 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
3153 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
3154 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
3155 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
3156 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
3157 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
3158 out << " // Check if the cuts configuration file was provided" << endl;
3159 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
3160 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
3161 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3162 out << " }" << endl;
3163 if (fFriendChainName=="") {
3164 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
3166 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
3167 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
3168 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
3170 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
3171 out << " chain->ls();" << endl;
3172 out << " return chain;" << endl;
3173 out << "}" << endl << endl;
3174 if (gSystem->AccessPathName("ConfigureCuts.C")) {
3175 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
3176 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
3177 msg += " AliLHCTagCuts *lhcCuts,\n";
3178 msg += " AliDetectorTagCuts *detCuts,\n";
3179 msg += " AliEventTagCuts *evCuts)";
3180 Info("WriteAnalysisMacro", "%s", msg.Data());
3183 if (!IsUsingTags() || fFriendChainName!="") {
3184 out <<"//________________________________________________________________________________" << endl;
3185 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
3187 out << "// Create a chain using url's from xml file" << endl;
3188 out << " TString filename;" << endl;
3189 out << " Int_t run = 0;" << endl;
3190 out << " TString treename = type;" << endl;
3191 out << " treename.ToLower();" << endl;
3192 out << " treename += \"Tree\";" << endl;
3193 out << " printf(\"***************************************\\n\");" << endl;
3194 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
3195 out << " printf(\"***************************************\\n\");" << endl;
3196 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
3197 out << " if (!coll) {" << endl;
3198 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3199 out << " return NULL;" << endl;
3200 out << " }" << endl;
3201 out << " AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();" << endl;
3202 out << " TChain *chain = new TChain(treename);" << endl;
3203 if(fFriendChainName!="") {
3204 out << " TChain *chainFriend = new TChain(treename);" << endl;
3206 out << " coll->Reset();" << endl;
3207 out << " while (coll->Next()) {" << endl;
3208 out << " filename = coll->GetTURL("");" << endl;
3209 out << " if (mgr) {" << endl;
3210 out << " Int_t nrun = AliAnalysisManager::GetRunFromAlienPath(filename);" << endl;
3211 out << " if (nrun && nrun != run) {" << endl;
3212 out << " printf(\"### Run number detected from chain: %d\\n\", nrun);" << endl;
3213 out << " mgr->SetRunFromPath(nrun);" << endl;
3214 out << " run = nrun;" << endl;
3215 out << " }" << endl;
3216 out << " }" << endl;
3217 out << " chain->Add(filename);" << endl;
3218 if(fFriendChainName!="") {
3219 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
3220 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3221 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3222 out << " chainFriend->Add(fileFriend.Data());" << endl;
3224 out << " }" << endl;
3225 out << " if (!chain->GetNtrees()) {" << endl;
3226 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
3227 out << " return NULL;" << endl;
3228 out << " }" << endl;
3229 if(fFriendChainName!="") {
3230 out << " chain->AddFriend(chainFriend);" << endl;
3232 out << " return chain;" << endl;
3233 out << "}" << endl << endl;
3235 if (hasANALYSISalice) {
3236 out <<"//________________________________________________________________________________" << endl;
3237 out << "Bool_t SetupPar(const char *package) {" << endl;
3238 out << "// Compile the package and set it up." << endl;
3239 out << " TString pkgdir = package;" << endl;
3240 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3241 out << " gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3242 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
3243 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
3244 out << " // Check for BUILD.sh and execute" << endl;
3245 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3246 out << " printf(\"*******************************\\n\");" << endl;
3247 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
3248 out << " printf(\"*******************************\\n\");" << endl;
3249 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3250 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3251 out << " gSystem->ChangeDirectory(cdir);" << endl;
3252 out << " return kFALSE;" << endl;
3253 out << " }" << endl;
3254 out << " } else {" << endl;
3255 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3256 out << " gSystem->ChangeDirectory(cdir);" << endl;
3257 out << " return kFALSE;" << endl;
3258 out << " }" << endl;
3259 out << " // Check for SETUP.C and execute" << endl;
3260 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3261 out << " printf(\"*******************************\\n\");" << endl;
3262 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
3263 out << " printf(\"*******************************\\n\");" << endl;
3264 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3265 out << " } else {" << endl;
3266 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3267 out << " gSystem->ChangeDirectory(cdir);" << endl;
3268 out << " return kFALSE;" << endl;
3269 out << " }" << endl;
3270 out << " // Restore original workdir" << endl;
3271 out << " gSystem->ChangeDirectory(cdir);" << endl;
3272 out << " return kTRUE;" << endl;
3275 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
3277 Bool_t copy = kTRUE;
3278 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3281 TString workdir = gGrid->GetHomeDirectory();
3282 workdir += fGridWorkingDir;
3283 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
3284 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
3285 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
3286 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
3287 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
3289 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
3290 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
3294 //______________________________________________________________________________
3295 void AliAnalysisAlien::WriteMergingMacro()
3297 // Write a macro to merge the outputs per master job.
3298 if (!fMergeViaJDL) return;
3299 if (!fOutputFiles.Length()) {
3300 Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3303 TString mergingMacro = fExecutable;
3304 mergingMacro.ReplaceAll(".sh","_merge.C");
3305 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3306 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3308 out.open(mergingMacro.Data(), ios::out);
3310 Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3313 Bool_t hasSTEERBase = kFALSE;
3314 Bool_t hasESD = kFALSE;
3315 Bool_t hasAOD = kFALSE;
3316 Bool_t hasANALYSIS = kFALSE;
3317 Bool_t hasANALYSISalice = kFALSE;
3318 Bool_t hasCORRFW = kFALSE;
3319 TString func = mergingMacro;
3321 func.ReplaceAll(".C", "");
3322 out << "void " << func.Data() << "(const char *dir, Int_t stage=0, Int_t laststage=0)" << endl;
3324 out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
3325 out << " TStopwatch timer;" << endl;
3326 out << " timer.Start();" << endl << endl;
3327 // Reset existing include path
3328 out << "// Reset existing include path and add current directory first in the search" << endl;
3329 out << " gSystem->SetIncludePath(\"-I.\");" << endl;
3330 if (!fExecutableCommand.Contains("aliroot")) {
3331 out << "// load base root libraries" << endl;
3332 out << " gSystem->Load(\"libTree\");" << endl;
3333 out << " gSystem->Load(\"libGeom\");" << endl;
3334 out << " gSystem->Load(\"libVMC\");" << endl;
3335 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
3336 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
3338 if (fAdditionalRootLibs.Length()) {
3339 // in principle libtree /lib geom libvmc etc. can go into this list, too
3340 out << "// Add aditional libraries" << endl;
3341 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3344 while((str=(TObjString*)next())) {
3345 if (str->GetString().Contains(".so"))
3346 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3348 if (list) delete list;
3350 out << "// Load analysis framework libraries" << endl;
3352 if (!fExecutableCommand.Contains("aliroot")) {
3353 out << " gSystem->Load(\"libSTEERBase\");" << endl;
3354 out << " gSystem->Load(\"libESD\");" << endl;
3355 out << " gSystem->Load(\"libAOD\");" << endl;
3357 out << " gSystem->Load(\"libANALYSIS\");" << endl;
3358 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3359 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3361 TIter next(fPackages);
3364 TString setupPar = "AliAnalysisAlien::SetupPar";
3365 while ((obj=next())) {
3366 pkgname = obj->GetName();
3367 if (pkgname == "STEERBase" ||
3368 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3369 if (pkgname == "ESD" ||
3370 pkgname == "ESD.par") hasESD = kTRUE;
3371 if (pkgname == "AOD" ||
3372 pkgname == "AOD.par") hasAOD = kTRUE;
3373 if (pkgname == "ANALYSIS" ||
3374 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
3375 if (pkgname == "ANALYSISalice" ||
3376 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3377 if (pkgname == "CORRFW" ||
3378 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
3380 if (hasANALYSISalice) setupPar = "SetupPar";
3381 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
3382 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3383 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
3384 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
3385 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
3386 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
3387 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
3388 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3389 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
3390 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3391 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
3392 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3393 out << "// Compile other par packages" << endl;
3395 while ((obj=next())) {
3396 pkgname = obj->GetName();
3397 if (pkgname == "STEERBase" ||
3398 pkgname == "STEERBase.par" ||
3400 pkgname == "ESD.par" ||
3402 pkgname == "AOD.par" ||
3403 pkgname == "ANALYSIS" ||
3404 pkgname == "ANALYSIS.par" ||
3405 pkgname == "ANALYSISalice" ||
3406 pkgname == "ANALYSISalice.par" ||
3407 pkgname == "CORRFW" ||
3408 pkgname == "CORRFW.par") continue;
3409 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3412 out << "// include path" << endl;
3413 // Get the include path from the interpreter and remove entries pointing to AliRoot
3414 out << " TString intPath = gInterpreter->GetIncludePath();" << endl;
3415 out << " TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3416 out << " TIter nextpath(listpaths);" << endl;
3417 out << " TObjString *pname;" << endl;
3418 out << " while ((pname=(TObjString*)nextpath())) {" << endl;
3419 out << " TString current = pname->GetName();" << endl;
3420 out << " if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3421 out << " gSystem->AddIncludePath(current);" << endl;
3422 out << " }" << endl;
3423 out << " if (listpaths) delete listpaths;" << endl;
3424 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3425 out << " gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3426 out << " printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3427 if (fAdditionalLibs.Length()) {
3428 out << "// Add aditional AliRoot libraries" << endl;
3429 TObjArray *list = fAdditionalLibs.Tokenize(" ");
3432 while((str=(TObjString*)next())) {
3433 if (str->GetString().Contains(".so"))
3434 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3436 if (list) delete list;
3439 out << "// Analysis source to be compiled at runtime (if any)" << endl;
3440 if (fAnalysisSource.Length()) {
3441 TObjArray *list = fAnalysisSource.Tokenize(" ");
3444 while((str=(TObjString*)next())) {
3445 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3447 if (list) delete list;
3451 if (fFastReadOption) {
3452 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 !!!");
3453 out << "// fast xrootd reading enabled" << endl;
3454 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3455 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3456 out << " gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3457 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3458 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3459 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3461 // Change temp directory to current one
3462 out << "// Set temporary merging directory to current one" << endl;
3463 out << " gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;
3464 out << "// Connect to AliEn" << endl;
3465 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
3466 out << " TString outputDir = dir;" << endl;
3467 out << " TString outputFiles = \"" << GetListOfFiles("out") << "\";" << endl;
3468 out << " TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
3469 out << " TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
3470 out << " TIter *iter = new TIter(list);" << endl;
3471 out << " TObjString *str;" << endl;
3472 out << " TString outputFile;" << endl;
3473 out << " Bool_t merged = kTRUE;" << endl;
3474 out << " while((str=(TObjString*)iter->Next())) {" << endl;
3475 out << " outputFile = str->GetString();" << endl;
3476 out << " if (outputFile.Contains(\"*\")) continue;" << endl;
3477 out << " Int_t index = outputFile.Index(\"@\");" << endl;
3478 out << " if (index > 0) outputFile.Remove(index);" << endl;
3479 out << " // Skip already merged outputs" << endl;
3480 out << " if (!gSystem->AccessPathName(outputFile)) {" << endl;
3481 out << " printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
3482 out << " continue;" << endl;
3483 out << " }" << endl;
3484 out << " if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
3485 out << " merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage);" << endl;
3486 out << " if (!merged) {" << endl;
3487 out << " printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
3488 out << " return;" << endl;
3489 out << " }" << endl;
3490 out << " }" << endl;
3491 out << " // all outputs merged, validate" << endl;
3492 out << " ofstream out;" << endl;
3493 out << " out.open(\"outputs_valid\", ios::out);" << endl;
3494 out << " out.close();" << endl;
3495 out << " // read the analysis manager from file" << endl;
3496 TString analysisFile = fExecutable;
3497 analysisFile.ReplaceAll(".sh", ".root");
3498 out << " if (laststage<10000) return;" << endl;
3499 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
3500 out << " if (!file) return;" << endl;
3501 out << " TIter nextkey(file->GetListOfKeys());" << endl;
3502 out << " AliAnalysisManager *mgr = 0;" << endl;
3503 out << " TKey *key;" << endl;
3504 out << " while ((key=(TKey*)nextkey())) {" << endl;
3505 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
3506 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
3507 out << " };" << endl;
3508 out << " if (!mgr) {" << endl;
3509 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
3510 out << " return;" << endl;
3511 out << " }" << endl << endl;
3512 out << " mgr->SetRunFromPath(mgr->GetRunFromAlienPath(dir));" << endl;
3513 out << " mgr->SetSkipTerminate(kFALSE);" << endl;
3514 out << " mgr->PrintStatus();" << endl;
3515 if (AliAnalysisManager::GetAnalysisManager()) {
3516 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3517 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3519 if (TestBit(AliAnalysisGrid::kTest))
3520 out << " AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3522 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3525 out << " TTree *tree = NULL;" << endl;
3526 out << " mgr->StartAnalysis(\"gridterminate\", tree);" << endl;
3527 out << "}" << endl << endl;
3528 if (hasANALYSISalice) {
3529 out <<"//________________________________________________________________________________" << endl;
3530 out << "Bool_t SetupPar(const char *package) {" << endl;
3531 out << "// Compile the package and set it up." << endl;
3532 out << " TString pkgdir = package;" << endl;
3533 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3534 out << " gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3535 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
3536 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
3537 out << " // Check for BUILD.sh and execute" << endl;
3538 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3539 out << " printf(\"*******************************\\n\");" << endl;
3540 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
3541 out << " printf(\"*******************************\\n\");" << endl;
3542 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3543 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3544 out << " gSystem->ChangeDirectory(cdir);" << endl;
3545 out << " return kFALSE;" << endl;
3546 out << " }" << endl;
3547 out << " } else {" << endl;
3548 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3549 out << " gSystem->ChangeDirectory(cdir);" << endl;
3550 out << " return kFALSE;" << endl;
3551 out << " }" << endl;
3552 out << " // Check for SETUP.C and execute" << endl;
3553 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3554 out << " printf(\"*******************************\\n\");" << endl;
3555 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
3556 out << " printf(\"*******************************\\n\");" << endl;
3557 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3558 out << " } else {" << endl;
3559 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3560 out << " gSystem->ChangeDirectory(cdir);" << endl;
3561 out << " return kFALSE;" << endl;
3562 out << " }" << endl;
3563 out << " // Restore original workdir" << endl;
3564 out << " gSystem->ChangeDirectory(cdir);" << endl;
3565 out << " return kTRUE;" << endl;
3569 Bool_t copy = kTRUE;
3570 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3573 TString workdir = gGrid->GetHomeDirectory();
3574 workdir += fGridWorkingDir;
3575 if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
3576 Info("WriteMergingMacro", "\n##### Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
3577 TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
3581 //______________________________________________________________________________
3582 Bool_t AliAnalysisAlien::SetupPar(const char *package)
3584 // Compile the par file archive pointed by <package>. This must be present in the current directory.
3585 // Note that for loading the compiled library. The current directory should have precedence in
3587 TString pkgdir = package;
3588 pkgdir.ReplaceAll(".par","");
3589 gSystem->Exec(TString::Format("tar xzf %s.par", pkgdir.Data()));
3590 TString cdir = gSystem->WorkingDirectory();
3591 gSystem->ChangeDirectory(pkgdir);
3592 // Check for BUILD.sh and execute
3593 if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
3594 printf("**************************************************\n");
3595 printf("*** Building PAR archive %s\n", package);
3596 printf("**************************************************\n");
3597 if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
3598 ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
3599 gSystem->ChangeDirectory(cdir);
3603 ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
3604 gSystem->ChangeDirectory(cdir);
3607 // Check for SETUP.C and execute
3608 if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
3609 printf("**************************************************\n");
3610 printf("*** Setup PAR archive %s\n", package);
3611 printf("**************************************************\n");
3612 gROOT->Macro("PROOF-INF/SETUP.C");
3613 printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
3615 ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
3616 gSystem->ChangeDirectory(cdir);
3619 // Restore original workdir
3620 gSystem->ChangeDirectory(cdir);
3624 //______________________________________________________________________________
3625 void AliAnalysisAlien::WriteExecutable()
3627 // Generate the alien executable script.
3628 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3630 out.open(fExecutable.Data(), ios::out);
3632 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
3635 out << "#!/bin/bash" << endl;
3636 // Make sure we can properly compile par files
3637 out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3638 out << "echo \"=========================================\"" << endl;
3639 out << "echo \"############## PATH : ##############\"" << endl;
3640 out << "echo $PATH" << endl;
3641 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3642 out << "echo $LD_LIBRARY_PATH" << endl;
3643 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3644 out << "echo $ROOTSYS" << endl;
3645 out << "echo \"############## which root : ##############\"" << endl;
3646 out << "which root" << endl;
3647 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3648 out << "echo $ALICE_ROOT" << endl;
3649 out << "echo \"############## which aliroot : ##############\"" << endl;
3650 out << "which aliroot" << endl;
3651 out << "echo \"############## system limits : ##############\"" << endl;
3652 out << "ulimit -a" << endl;
3653 out << "echo \"############## memory : ##############\"" << endl;
3654 out << "free -m" << endl;
3655 out << "echo \"=========================================\"" << endl << endl;
3656 out << fExecutableCommand << " ";
3657 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
3658 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
3659 out << "echo \"############## memory after: ##############\"" << endl;
3660 out << "free -m" << endl;
3662 Bool_t copy = kTRUE;
3663 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3666 TString workdir = gGrid->GetHomeDirectory();
3667 TString bindir = Form("%s/bin", workdir.Data());
3668 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
3669 workdir += fGridWorkingDir;
3670 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
3671 if (FileExists(executable)) gGrid->Rm(executable);
3672 Info("WriteExecutable", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
3673 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
3677 //______________________________________________________________________________
3678 void AliAnalysisAlien::WriteMergeExecutable()
3680 // Generate the alien executable script for the merging job.
3681 if (!fMergeViaJDL) return;
3682 TString mergeExec = fExecutable;
3683 mergeExec.ReplaceAll(".sh", "_merge.sh");
3684 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3686 out.open(mergeExec.Data(), ios::out);
3688 Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
3691 out << "#!/bin/bash" << endl;
3692 // Make sure we can properly compile par files
3693 out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
3694 out << "echo \"=========================================\"" << endl;
3695 out << "echo \"############## PATH : ##############\"" << endl;
3696 out << "echo $PATH" << endl;
3697 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
3698 out << "echo $LD_LIBRARY_PATH" << endl;
3699 out << "echo \"############## ROOTSYS : ##############\"" << endl;
3700 out << "echo $ROOTSYS" << endl;
3701 out << "echo \"############## which root : ##############\"" << endl;
3702 out << "which root" << endl;
3703 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
3704 out << "echo $ALICE_ROOT" << endl;
3705 out << "echo \"############## which aliroot : ##############\"" << endl;
3706 out << "which aliroot" << endl;
3707 out << "echo \"############## system limits : ##############\"" << endl;
3708 out << "ulimit -a" << endl;
3709 out << "echo \"############## memory : ##############\"" << endl;
3710 out << "free -m" << endl;
3711 out << "echo \"=========================================\"" << endl << endl;
3712 TString mergeMacro = fExecutable;
3713 mergeMacro.ReplaceAll(".sh", "_merge.C");
3714 if (IsOneStageMerging())
3715 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
3717 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2,$3)\"" << endl;
3718 out << fExecutableCommand << " " << "$ARG" << endl;
3719 out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
3720 out << "echo \"############## memory after: ##############\"" << endl;
3721 out << "free -m" << endl;
3723 Bool_t copy = kTRUE;
3724 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3727 TString workdir = gGrid->GetHomeDirectory();
3728 TString bindir = Form("%s/bin", workdir.Data());
3729 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
3730 workdir += fGridWorkingDir;
3731 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
3732 if (FileExists(executable)) gGrid->Rm(executable);
3733 Info("WriteMergeExecutable", "\n##### Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
3734 TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
3738 //______________________________________________________________________________
3739 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
3741 // Write the production file to be submitted by LPM manager. The format is:
3742 // First line: full_path_to_jdl estimated_no_subjobs_per_master
3743 // Next lines: full_path_to_dataset XXX (XXX is a string)
3744 // To submit, one has to: submit jdl XXX for all lines
3746 out.open(filename, ios::out);
3748 Error("WriteProductionFile", "Bad file name: %s", filename);
3752 if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice"))
3753 workdir = gGrid->GetHomeDirectory();
3754 workdir += fGridWorkingDir;
3755 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
3756 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
3757 out << locjdl << " " << njobspermaster << endl;
3758 Int_t nmasterjobs = fInputFiles->GetEntries();
3759 for (Int_t i=0; i<nmasterjobs; i++) {
3760 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3761 runOutDir.ReplaceAll(".xml", "");
3763 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
3765 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
3768 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
3769 if (FileExists(filename)) gGrid->Rm(filename);
3770 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
3774 //______________________________________________________________________________
3775 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
3777 // Generate the alien validation script.
3778 // Generate the validation script
3780 if (fValidationScript.IsNull()) {
3781 fValidationScript = fExecutable;
3782 fValidationScript.ReplaceAll(".sh", "_validation.sh");
3784 TString validationScript = fValidationScript;
3785 if (merge) validationScript.ReplaceAll(".sh", "_merge.sh");
3787 Error("WriteValidationScript", "Alien connection required");
3790 if (!fTerminateFiles.IsNull()) {
3791 fTerminateFiles.Strip();
3792 fTerminateFiles.ReplaceAll(" ",",");
3794 TString outStream = "";
3795 if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
3796 if (!TestBit(AliAnalysisGrid::kSubmit)) {
3798 out.open(validationScript, ios::out);
3799 out << "#!/bin/bash" << endl;
3800 out << "##################################################" << endl;
3801 out << "validateout=`dirname $0`" << endl;
3802 out << "validatetime=`date`" << endl;
3803 out << "validated=\"0\";" << endl;
3804 out << "error=0" << endl;
3805 out << "if [ -z $validateout ]" << endl;
3806 out << "then" << endl;
3807 out << " validateout=\".\"" << endl;
3808 out << "fi" << endl << endl;
3809 out << "cd $validateout;" << endl;
3810 out << "validateworkdir=`pwd`;" << endl << endl;
3811 out << "echo \"*******************************************************\"" << outStream << endl;
3812 out << "echo \"* Automatically generated validation script *\"" << outStream << endl;
3814 out << "echo \"* Time: $validatetime \"" << outStream << endl;
3815 out << "echo \"* Dir: $validateout\"" << outStream << endl;
3816 out << "echo \"* Workdir: $validateworkdir\"" << outStream << endl;
3817 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3818 out << "ls -la ./" << outStream << endl;
3819 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl << endl;
3820 out << "##################################################" << endl;
3823 out << "if [ ! -f stderr ] ; then" << endl;
3824 out << " error=1" << endl;
3825 out << " echo \"* ########## Job not validated - no stderr ###\" " << outStream << endl;
3826 out << " echo \"Error = $error\" " << outStream << endl;
3827 out << "fi" << endl;
3829 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
3830 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
3831 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
3832 out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
3835 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
3836 out << " error=1" << endl;
3837 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << outStream << endl;
3838 out << " echo \"$parArch\" " << outStream << endl;
3839 out << " echo \"Error = $error\" " << outStream << endl;
3840 out << "fi" << endl;
3842 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
3843 out << " error=1" << endl;
3844 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << outStream << endl;
3845 out << " echo \"$segViol\" " << outStream << endl;
3846 out << " echo \"Error = $error\" " << outStream << endl;
3847 out << "fi" << endl;
3849 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
3850 out << " error=1" << endl;
3851 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << outStream << endl;
3852 out << " echo \"$segFault\" " << outStream << endl;
3853 out << " echo \"Error = $error\" " << outStream << endl;
3854 out << "fi" << endl;
3856 out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
3857 out << " error=1" << endl;
3858 out << " echo \"* ########## Job not validated - *** glibc detected *** ###\" " << outStream << endl;
3859 out << " echo \"$glibcErr\" " << outStream << endl;
3860 out << " echo \"Error = $error\" " << outStream << endl;
3861 out << "fi" << endl;
3863 // Part dedicated to the specific analyses running into the train
3865 TString outputFiles = fOutputFiles;
3866 if (merge && !fTerminateFiles.IsNull()) {
3868 outputFiles += fTerminateFiles;
3870 TObjArray *arr = outputFiles.Tokenize(",");
3873 while (!merge && (os=(TObjString*)next1())) {
3874 // No need to validate outputs produced by merging since the merging macro does this
3875 outputFile = os->GetString();
3876 Int_t index = outputFile.Index("@");
3877 if (index > 0) outputFile.Remove(index);
3878 if (fTerminateFiles.Contains(outputFile)) continue;
3879 if (outputFile.Contains("*")) continue;
3880 out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
3881 out << " error=1" << endl;
3882 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\"" << outStream << endl;
3883 out << " echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
3884 out << "fi" << endl;
3887 out << "if ! [ -f outputs_valid ] ; then" << endl;
3888 out << " error=1" << endl;
3889 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
3890 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
3891 out << "fi" << endl;
3893 out << "if [ $error = 0 ] ; then" << endl;
3894 out << " echo \"* ---------------- Job Validated ------------------*\"" << outStream << endl;
3895 if (!IsKeepLogs()) {
3896 out << " echo \"* === Logs std* will be deleted === \"" << endl;
3898 out << " rm -f std*" << endl;
3900 out << "fi" << endl;
3902 out << "echo \"* ----------------------------------------------------*\"" << outStream << endl;
3903 out << "echo \"*******************************************************\"" << outStream << endl;
3904 out << "cd -" << endl;
3905 out << "exit $error" << endl;
3907 Bool_t copy = kTRUE;
3908 if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3911 TString workdir = gGrid->GetHomeDirectory();
3912 workdir += fGridWorkingDir;
3913 Info("WriteValidationScript", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
3914 if (FileExists(validationScript)) gGrid->Rm(validationScript);
3915 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));