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"
29 #include "TObjString.h"
30 #include "TObjArray.h"
32 #include "TGridResult.h"
33 #include "TGridCollection.h"
35 #include "TGridJobStatusList.h"
36 #include "TGridJobStatus.h"
37 #include "TFileMerger.h"
38 #include "AliAnalysisManager.h"
39 #include "AliVEventHandler.h"
40 #include "AliAnalysisDataContainer.h"
41 #include "AliAnalysisAlien.h"
43 ClassImp(AliAnalysisAlien)
45 //______________________________________________________________________________
46 AliAnalysisAlien::AliAnalysisAlien()
52 fSplitMaxInputFileNumber(0),
54 fMasterResubmitThreshold(0),
71 fAdditionalRootLibs(),
102 //______________________________________________________________________________
103 AliAnalysisAlien::AliAnalysisAlien(const char *name)
104 :AliAnalysisGrid(name),
109 fSplitMaxInputFileNumber(0),
111 fMasterResubmitThreshold(0),
123 fExecutableCommand(),
128 fAdditionalRootLibs(),
159 //______________________________________________________________________________
160 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
161 :AliAnalysisGrid(other),
164 fPrice(other.fPrice),
166 fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
167 fMaxInitFailed(other.fMaxInitFailed),
168 fMasterResubmitThreshold(other.fMasterResubmitThreshold),
169 fNtestFiles(other.fNtestFiles),
170 fNrunsPerMaster(other.fNrunsPerMaster),
171 fMaxMergeFiles(other.fMaxMergeFiles),
172 fNsubmitted(other.fNsubmitted),
173 fProductionMode(other.fProductionMode),
174 fOutputToRunNo(other.fOutputToRunNo),
175 fMergeViaJDL(other.fMergeViaJDL),
176 fFastReadOption(other.fFastReadOption),
177 fOverwriteMode(other.fOverwriteMode),
178 fRunNumbers(other.fRunNumbers),
179 fExecutable(other.fExecutable),
180 fExecutableCommand(other.fExecutableCommand),
181 fArguments(other.fArguments),
182 fExecutableArgs(other.fExecutableArgs),
183 fAnalysisMacro(other.fAnalysisMacro),
184 fAnalysisSource(other.fAnalysisSource),
185 fAdditionalRootLibs(other.fAdditionalRootLibs),
186 fAdditionalLibs(other.fAdditionalLibs),
187 fSplitMode(other.fSplitMode),
188 fAPIVersion(other.fAPIVersion),
189 fROOTVersion(other.fROOTVersion),
190 fAliROOTVersion(other.fAliROOTVersion),
191 fExternalPackages(other.fExternalPackages),
193 fGridWorkingDir(other.fGridWorkingDir),
194 fGridDataDir(other.fGridDataDir),
195 fDataPattern(other.fDataPattern),
196 fGridOutputDir(other.fGridOutputDir),
197 fOutputArchive(other.fOutputArchive),
198 fOutputFiles(other.fOutputFiles),
199 fInputFormat(other.fInputFormat),
200 fDatasetName(other.fDatasetName),
201 fJDLName(other.fJDLName),
202 fMergeExcludes(other.fMergeExcludes),
203 fIncludePath(other.fIncludePath),
204 fCloseSE(other.fCloseSE),
205 fFriendChainName(other.fFriendChainName),
206 fJobTag(other.fJobTag),
207 fOutputSingle(other.fOutputSingle),
208 fRunPrefix(other.fRunPrefix),
213 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
214 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
215 fRunRange[0] = other.fRunRange[0];
216 fRunRange[1] = other.fRunRange[1];
217 if (other.fInputFiles) {
218 fInputFiles = new TObjArray();
219 TIter next(other.fInputFiles);
221 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
222 fInputFiles->SetOwner();
224 if (other.fPackages) {
225 fPackages = new TObjArray();
226 TIter next(other.fPackages);
228 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
229 fPackages->SetOwner();
233 //______________________________________________________________________________
234 AliAnalysisAlien::~AliAnalysisAlien()
237 if (fGridJDL) delete fGridJDL;
238 if (fMergingJDL) delete fMergingJDL;
239 if (fInputFiles) delete fInputFiles;
240 if (fPackages) delete fPackages;
243 //______________________________________________________________________________
244 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
247 if (this != &other) {
248 AliAnalysisGrid::operator=(other);
249 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
250 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
251 fPrice = other.fPrice;
253 fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
254 fMaxInitFailed = other.fMaxInitFailed;
255 fMasterResubmitThreshold = other.fMasterResubmitThreshold;
256 fNtestFiles = other.fNtestFiles;
257 fNrunsPerMaster = other.fNrunsPerMaster;
258 fMaxMergeFiles = other.fMaxMergeFiles;
259 fNsubmitted = other.fNsubmitted;
260 fProductionMode = other.fProductionMode;
261 fOutputToRunNo = other.fOutputToRunNo;
262 fMergeViaJDL = other.fMergeViaJDL;
263 fFastReadOption = other.fFastReadOption;
264 fOverwriteMode = other.fOverwriteMode;
265 fRunNumbers = other.fRunNumbers;
266 fExecutable = other.fExecutable;
267 fExecutableCommand = other.fExecutableCommand;
268 fArguments = other.fArguments;
269 fExecutableArgs = other.fExecutableArgs;
270 fAnalysisMacro = other.fAnalysisMacro;
271 fAnalysisSource = other.fAnalysisSource;
272 fAdditionalRootLibs = other.fAdditionalRootLibs;
273 fAdditionalLibs = other.fAdditionalLibs;
274 fSplitMode = other.fSplitMode;
275 fAPIVersion = other.fAPIVersion;
276 fROOTVersion = other.fROOTVersion;
277 fAliROOTVersion = other.fAliROOTVersion;
278 fExternalPackages = other.fExternalPackages;
280 fGridWorkingDir = other.fGridWorkingDir;
281 fGridDataDir = other.fGridDataDir;
282 fDataPattern = other.fDataPattern;
283 fGridOutputDir = other.fGridOutputDir;
284 fOutputArchive = other.fOutputArchive;
285 fOutputFiles = other.fOutputFiles;
286 fInputFormat = other.fInputFormat;
287 fDatasetName = other.fDatasetName;
288 fJDLName = other.fJDLName;
289 fMergeExcludes = other.fMergeExcludes;
290 fIncludePath = other.fIncludePath;
291 fCloseSE = other.fCloseSE;
292 fFriendChainName = other.fFriendChainName;
293 fJobTag = other.fJobTag;
294 fOutputSingle = other.fOutputSingle;
295 fRunPrefix = other.fRunPrefix;
296 if (other.fInputFiles) {
297 fInputFiles = new TObjArray();
298 TIter next(other.fInputFiles);
300 while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
301 fInputFiles->SetOwner();
303 if (other.fPackages) {
304 fPackages = new TObjArray();
305 TIter next(other.fPackages);
307 while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
308 fPackages->SetOwner();
314 //______________________________________________________________________________
315 void AliAnalysisAlien::AddIncludePath(const char *path)
317 // Add include path in the remote analysis macro.
319 if (p.Contains("-I")) fIncludePath += Form("%s ", path);
320 else fIncludePath += Form("-I%s ", path);
323 //______________________________________________________________________________
324 void AliAnalysisAlien::AddRunNumber(Int_t run)
326 // Add a run number to the list of runs to be processed.
327 if (fRunNumbers.Length()) fRunNumbers += " ";
328 fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
331 //______________________________________________________________________________
332 void AliAnalysisAlien::AddRunNumber(const char* run)
334 // Add a run number to the list of runs to be processed.
335 if (fRunNumbers.Length()) fRunNumbers += " ";
339 //______________________________________________________________________________
340 void AliAnalysisAlien::AddDataFile(const char *lfn)
342 // Adds a data file to the input to be analysed. The file should be a valid LFN
343 // or point to an existing file in the alien workdir.
344 if (!fInputFiles) fInputFiles = new TObjArray();
345 fInputFiles->Add(new TObjString(lfn));
348 //______________________________________________________________________________
349 void AliAnalysisAlien::AddExternalPackage(const char *package)
351 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
352 if (fExternalPackages) fExternalPackages += " ";
353 fExternalPackages += package;
356 //______________________________________________________________________________
357 Bool_t AliAnalysisAlien::Connect()
359 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
360 if (gGrid && gGrid->IsConnected()) return kTRUE;
361 if (!gSystem->Getenv("alien_API_USER")) {
362 Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
363 gSystem->Getenv("UID"));
367 Info("Connect", "Trying to connect to AliEn ...");
368 TGrid::Connect("alien://");
370 if (!gGrid || !gGrid->IsConnected()) {
371 Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
374 fUser = gGrid->GetUser();
375 Info("Connect", "\n##### Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
379 //______________________________________________________________________________
380 void AliAnalysisAlien::CdWork()
382 // Check validity of alien workspace. Create directory if possible.
384 Error("CdWork", "Alien connection required");
387 TString homedir = gGrid->GetHomeDirectory();
388 TString workdir = homedir + fGridWorkingDir;
389 if (DirectoryExists(workdir)) {
393 // Work directory not existing - create it
395 if (gGrid->Mkdir(workdir)) {
396 gGrid->Cd(fGridWorkingDir);
397 Info("CreateJDL", "\n##### Created alien working directory %s", fGridWorkingDir.Data());
399 Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
400 workdir.Data(), homedir.Data());
401 fGridWorkingDir = "";
405 //______________________________________________________________________________
406 Bool_t AliAnalysisAlien::CheckInputData()
408 // Check validity of input data. If necessary, create xml files.
409 if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
410 if (!fGridDataDir.Length()) {
411 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
414 Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
417 // Process declared files
418 Bool_t is_collection = kFALSE;
419 Bool_t is_xml = kFALSE;
420 Bool_t use_tags = kFALSE;
421 Bool_t checked = kFALSE;
424 TString workdir = gGrid->GetHomeDirectory();
425 workdir += fGridWorkingDir;
428 TIter next(fInputFiles);
429 while ((objstr=(TObjString*)next())) {
432 file += objstr->GetString();
433 // Store full lfn path
434 if (FileExists(file)) objstr->SetString(file);
436 file = objstr->GetName();
437 if (!FileExists(objstr->GetName())) {
438 Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
439 objstr->GetName(), workdir.Data());
443 Bool_t iscoll, isxml, usetags;
444 CheckDataType(file, iscoll, isxml, usetags);
447 is_collection = iscoll;
450 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
452 if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
453 Error("CheckInputData", "Some conflict was found in the types of inputs");
459 // Process requested run numbers
460 if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
461 // Check validity of alien data directory
462 if (!fGridDataDir.Length()) {
463 Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
466 if (!DirectoryExists(fGridDataDir)) {
467 Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
471 Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
475 if (checked && !is_xml) {
476 Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
479 // Check validity of run number(s)
483 TString schunk, schunk2;
487 use_tags = fDataPattern.Contains("tag");
488 TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
490 if (use_tags != fDataPattern.Contains("tag")) {
491 Error("CheckInputData", "Cannot mix input files using/not using tags");
494 if (fRunNumbers.Length()) {
495 Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
496 arr = fRunNumbers.Tokenize(" ");
498 while ((os=(TObjString*)next())) {
499 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
500 if (!DirectoryExists(path)) {
501 Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
504 path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
505 TString msg = "\n##### file: ";
507 msg += " type: xml_collection;";
508 if (use_tags) msg += " using_tags: Yes";
509 else msg += " using_tags: No";
510 Info("CheckDataType", msg.Data());
511 if (fNrunsPerMaster<2) {
512 AddDataFile(Form("%s.xml", os->GetString().Data()));
515 if (((nruns-1)%fNrunsPerMaster) == 0) {
516 schunk = os->GetString();
518 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
519 schunk += Form("_%s.xml", os->GetString().Data());
525 Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
526 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
527 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
528 if (!DirectoryExists(path)) {
529 // Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
532 path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
533 TString msg = "\n##### file: ";
535 msg += " type: xml_collection;";
536 if (use_tags) msg += " using_tags: Yes";
537 else msg += " using_tags: No";
538 Info("CheckDataType", msg.Data());
539 if (fNrunsPerMaster<2) {
540 AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
543 if (((nruns-1)%fNrunsPerMaster) == 0) {
544 schunk = Form("%s%d", fRunPrefix.Data(),irun);
546 schunk2 = Form("_%s%d.xml", fRunPrefix.Data(), irun);
547 if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
560 //______________________________________________________________________________
561 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
563 // Create dataset for the grid data directory + run number.
564 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
566 Error("CreateDataset", "Cannot create dataset with no grid connection");
572 TString workdir = gGrid->GetHomeDirectory();
573 workdir += fGridWorkingDir;
575 // Compose the 'find' command arguments
577 TString options = "-x collection ";
578 if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
579 TString conditions = "";
584 TString schunk, schunk2;
585 TGridCollection *cbase=0, *cadd=0;
586 if (!fRunNumbers.Length() && !fRunRange[0]) {
587 if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
588 // Make a single data collection from data directory.
590 if (!DirectoryExists(path)) {
591 Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
595 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
596 else file = Form("%s.xml", gSystem->BaseName(path));
597 if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
603 command += conditions;
604 printf("command: %s\n", command.Data());
605 TGridResult *res = gGrid->Command(command);
607 // Write standard output to file
608 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
610 Bool_t fileExists = FileExists(file);
611 if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
612 // Copy xml file to alien space
613 if (fileExists) gGrid->Rm(file);
614 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
615 if (!FileExists(file)) {
616 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
619 // Update list of files to be processed.
621 AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
625 if (fRunNumbers.Length()) {
626 TObjArray *arr = fRunNumbers.Tokenize(" ");
629 while ((os=(TObjString*)next())) {
630 path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
631 if (!DirectoryExists(path)) continue;
633 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
634 else file = Form("%s.xml", os->GetString().Data());
635 // If local collection file does not exist, create it via 'find' command.
636 if (gSystem->AccessPathName(file)) {
641 command += conditions;
642 TGridResult *res = gGrid->Command(command);
644 // Write standard output to file
645 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
647 if (TestBit(AliAnalysisGrid::kTest)) break;
648 // Check if there is one run per master job.
649 if (fNrunsPerMaster<2) {
650 if (FileExists(file)) {
651 if (fOverwriteMode) gGrid->Rm(file);
653 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
657 // Copy xml file to alien space
658 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
659 if (!FileExists(file)) {
660 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
666 if (((nruns-1)%fNrunsPerMaster) == 0) {
667 schunk = os->GetString();
668 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
670 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
671 printf(" Merging collection <%s> into masterjob input...\n", file.Data());
675 if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
678 schunk += Form("_%s.xml", os->GetString().Data());
679 if (FileExists(schunk)) {
680 if (fOverwriteMode) gGrid->Rm(file);
682 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
686 printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
687 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
688 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
689 if (!FileExists(schunk)) {
690 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
698 // Process a full run range.
699 for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
700 path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
701 if (!DirectoryExists(path)) continue;
703 if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
704 else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
705 if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
706 if (fOverwriteMode) gGrid->Rm(file);
708 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
712 // If local collection file does not exist, create it via 'find' command.
713 if (gSystem->AccessPathName(file) || fOverwriteMode) {
718 command += conditions;
719 TGridResult *res = gGrid->Command(command);
721 // Write standard output to file
722 gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
724 if (TestBit(AliAnalysisGrid::kTest)) break;
725 // Check if there is one run per master job.
726 if (fNrunsPerMaster<2) {
727 if (FileExists(file)) {
728 if (fOverwriteMode) gGrid->Rm(file);
730 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", file.Data());
734 // Copy xml file to alien space
735 TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
736 if (!FileExists(file)) {
737 Error("CreateDataset", "Command %s did NOT succeed", command.Data());
742 // Check if the collection for the chunk exist locally.
743 Int_t nchunk = (nruns-1)/fNrunsPerMaster;
744 if (FileExists(fInputFiles->At(nchunk)->GetName())) {
745 if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
748 printf(" Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
749 if (((nruns-1)%fNrunsPerMaster) == 0) {
750 schunk = Form("%s%d", fRunPrefix.Data(), irun);
751 cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
753 cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
757 schunk2 = Form("%s_%s%d.xml", schunk.Data(), fRunPrefix.Data(), irun);
758 if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
762 if (FileExists(schunk)) {
763 if (fOverwriteMode) gGrid->Rm(schunk);
765 Info("CreateDataset", "\n##### Dataset %s exist. Skipping creation...", schunk.Data());
769 printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
770 cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
771 if (FileExists(schunk)) {
772 if (fOverwriteMode) gGrid->Rm(schunk);
774 Info("CreateDataset", "\n##### Dataset %s exist. Skipping copy...", schunk.Data());
778 TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
779 if (!FileExists(schunk)) {
780 Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
789 //______________________________________________________________________________
790 Bool_t AliAnalysisAlien::CreateJDL()
792 // Generate a JDL file according to current settings. The name of the file is
793 // specified by fJDLName.
794 Bool_t error = kFALSE;
797 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
798 Bool_t generate = kTRUE;
799 if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
801 Error("CreateJDL", "Alien connection required");
804 // Check validity of alien workspace
806 TString workdir = gGrid->GetHomeDirectory();
807 workdir += fGridWorkingDir;
811 Error("CreateJDL()", "Define some input files for your analysis.");
814 // Compose list of input files
815 // Check if output files were defined
816 if (!fOutputFiles.Length()) {
817 Error("CreateJDL", "You must define at least one output file");
820 // Check if an output directory was defined and valid
821 if (!fGridOutputDir.Length()) {
822 Error("CreateJDL", "You must define AliEn output directory");
825 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
826 if (!DirectoryExists(fGridOutputDir)) {
827 if (gGrid->Mkdir(fGridOutputDir)) {
828 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
830 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
836 // Exit if any error up to now
837 if (error) return kFALSE;
839 if (!fUser.IsNull()) {
840 fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
841 fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
843 fGridJDL->SetExecutable(fExecutable, "This is the startup script");
844 TString mergeExec = fExecutable;
845 mergeExec.ReplaceAll(".sh", "_merge.sh");
846 fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
847 mergeExec.ReplaceAll(".sh", ".C");
848 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
849 if (!fArguments.IsNull())
850 fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
851 fMergingJDL->SetArguments("$1");
852 fGridJDL->SetTTL((UInt_t)fTTL);
853 fMergingJDL->SetTTL((UInt_t)fTTL);
854 if (fMaxInitFailed > 0) {
855 fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
856 fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
858 if (fSplitMaxInputFileNumber > 0) {
859 fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
860 fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
862 if (fSplitMode.Length()) {
863 fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
864 fGridJDL->SetDescription("Split", "We split per SE or file");
866 if (!fAliROOTVersion.IsNull()) {
867 fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
868 fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
870 if (!fROOTVersion.IsNull()) {
871 fGridJDL->AddToPackages("ROOT", fROOTVersion);
872 fMergingJDL->AddToPackages("ROOT", fROOTVersion);
874 if (!fAPIVersion.IsNull()) {
875 fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
876 fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
878 if (!fExternalPackages.IsNull()) {
879 arr = fExternalPackages.Tokenize(" ");
881 while ((os=(TObjString*)next())) {
882 TString pkgname = os->GetString();
883 Int_t index = pkgname.Index("::");
884 TString pkgversion = pkgname(index+2, pkgname.Length());
885 pkgname.Remove(index);
886 fGridJDL->AddToPackages(pkgname, pkgversion);
887 fMergingJDL->AddToPackages(pkgname, pkgversion);
891 fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
892 fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
893 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
894 TString analysisFile = fExecutable;
895 analysisFile.ReplaceAll(".sh", ".root");
896 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
897 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
898 fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
899 if (fAdditionalLibs.Length()) {
900 arr = fAdditionalLibs.Tokenize(" ");
902 while ((os=(TObjString*)next())) {
903 if (os->GetString().Contains(".so")) continue;
904 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
905 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
910 TIter next(fPackages);
912 while ((obj=next())) {
913 fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
914 fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
917 if (fOutputArchive.Length()) {
918 arr = fOutputArchive.Tokenize(" ");
920 Bool_t first = kTRUE;
921 const char *comment = "Files to be archived";
922 const char *comment1 = comment;
923 while ((os=(TObjString*)next())) {
924 if (!first) comment = NULL;
925 if (!os->GetString().Contains("@") && fCloseSE.Length())
926 fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
928 fGridJDL->AddToOutputArchive(os->GetString(), comment);
932 TString outputArchive = fOutputArchive;
933 if (!fMergeExcludes.IsNull()) {
934 arr = fMergeExcludes.Tokenize(" ");
936 while ((os=(TObjString*)next1())) {
937 outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
938 outputArchive.ReplaceAll(os->GetString(),"");
942 arr = outputArchive.Tokenize(" ");
946 while ((os=(TObjString*)next2())) {
947 if (!first) comment = NULL;
948 if (!os->GetString().Contains("@") && fCloseSE.Length())
949 fMergingJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
951 fMergingJDL->AddToOutputArchive(os->GetString(), comment);
956 arr = fOutputFiles.Tokenize(" ");
958 Bool_t first = kTRUE;
959 const char *comment = "Files to be archived";
960 const char *comment1 = comment;
961 while ((os=(TObjString*)next())) {
962 // Ignore ouputs in jdl that are also in outputarchive
963 TString sout = os->GetString();
964 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
965 if (fOutputArchive.Contains(sout)) continue;
966 if (!first) comment = NULL;
967 if (!os->GetString().Contains("@") && fCloseSE.Length())
968 fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
970 fGridJDL->AddToOutputSandbox(os->GetString(), comment);
974 if (fOutputFiles.Length()) {
975 TString outputFiles = fOutputFiles;
976 if (!fMergeExcludes.IsNull()) {
977 arr = fMergeExcludes.Tokenize(" ");
979 while ((os=(TObjString*)next1())) {
980 outputFiles.ReplaceAll(Form("%s,",os->GetString().Data()),"");
981 outputFiles.ReplaceAll(os->GetString(),"");
985 arr = outputFiles.Tokenize(" ");
989 while ((os=(TObjString*)next2())) {
990 // Ignore ouputs in jdl that are also in outputarchive
991 TString sout = os->GetString();
992 if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
993 if (fOutputArchive.Contains(sout)) continue;
994 if (!first) comment = NULL;
995 if (!os->GetString().Contains("@") && fCloseSE.Length())
996 fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment);
998 fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1002 fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1003 fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1004 TString validationScript = fExecutable;
1005 validationScript.ReplaceAll(".sh", "_validation.sh");
1006 fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1007 validationScript = fExecutable;
1008 validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
1009 fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1010 if (fMasterResubmitThreshold) {
1011 fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1012 fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1014 // Write a jdl with 2 input parameters: collection name and output dir name.
1017 // Copy jdl to grid workspace
1019 // Check if an output directory was defined and valid
1020 if (!fGridOutputDir.Length()) {
1021 Error("CreateJDL", "You must define AliEn output directory");
1024 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1025 if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1026 if (gGrid->Mkdir(fGridOutputDir)) {
1027 Info("CreateJDL", "\n##### Created alien output directory %s", fGridOutputDir.Data());
1029 Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1035 if (TestBit(AliAnalysisGrid::kSubmit)) {
1036 TString mergeJDLName = fExecutable;
1037 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1038 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1039 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1040 if (fProductionMode) {
1041 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1042 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1044 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1045 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1046 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1047 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1049 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1050 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1053 if (fAdditionalLibs.Length()) {
1054 arr = fAdditionalLibs.Tokenize(" ");
1057 while ((os=(TObjString*)next())) {
1058 if (os->GetString().Contains(".so")) continue;
1059 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1060 if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1061 TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1066 TIter next(fPackages);
1068 while ((obj=next())) {
1069 if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1070 Info("CreateJDL", "\n##### Copying dependency: <%s> to your alien workspace", obj->GetName());
1071 TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1078 //______________________________________________________________________________
1079 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1081 // Writes one or more JDL's corresponding to findex. If findex is negative,
1082 // all run numbers are considered in one go (jdl). For non-negative indices
1083 // they correspond to the indices in the array fInputFiles.
1084 if (!fInputFiles) return kFALSE;
1086 TString workdir = gGrid->GetHomeDirectory();
1087 workdir += fGridWorkingDir;
1089 if (!fRunNumbers.Length() && !fRunRange[0]) {
1090 // One jdl with no parameters in case input data is specified by name.
1091 TIter next(fInputFiles);
1092 while ((os=(TObjString*)next()))
1093 fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()), "Input xml collections");
1094 if (!fOutputSingle.IsNull())
1095 fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1097 fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1098 fMergingJDL->SetOutputDirectory(fGridOutputDir);
1101 // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1102 fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1103 if (!fOutputSingle.IsNull()) {
1104 if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1105 else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1107 fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1108 fMergingJDL->SetOutputDirectory(Form("%s/$1", fGridOutputDir.Data()), "Output directory");
1113 // Generate the JDL as a string
1114 TString sjdl = fGridJDL->Generate();
1115 TString sjdl1 = fMergingJDL->Generate();
1117 sjdl.ReplaceAll("\"LF:", "\n \"LF:");
1118 sjdl.ReplaceAll("(member", "\n (member");
1119 sjdl.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1120 sjdl.ReplaceAll("{", "{\n ");
1121 sjdl.ReplaceAll("};", "\n};");
1122 sjdl.ReplaceAll("{\n \n", "{\n");
1123 sjdl.ReplaceAll("\n\n", "\n");
1124 sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1125 sjdl1.ReplaceAll("\"LF:", "\n \"LF:");
1126 sjdl1.ReplaceAll("(member", "\n (member");
1127 sjdl1.ReplaceAll("\",\"VO_", "\",\n \"VO_");
1128 sjdl1.ReplaceAll("{", "{\n ");
1129 sjdl1.ReplaceAll("};", "\n};");
1130 sjdl1.ReplaceAll("{\n \n", "{\n");
1131 sjdl1.ReplaceAll("\n\n", "\n");
1132 sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1133 sjdl += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1134 sjdl.Prepend(Form("Jobtag = {\n \"comment:%s\"\n};\n", fJobTag.Data()));
1135 index = sjdl.Index("JDLVariables");
1136 if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1137 sjdl1 += "JDLVariables = \n{\n \"Packages\",\n \"OutputDir\"\n};\n";
1138 sjdl1.Prepend(Form("Jobtag = {\n \"comment:Merging_%s\"\n};\n", fJobTag.Data()));
1139 index = sjdl1.Index("JDLVariables");
1140 if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1141 // Write jdl to file
1143 out.open(fJDLName.Data(), ios::out);
1145 Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1148 out << sjdl << endl;
1149 TString mergeJDLName = fExecutable;
1150 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1153 out1.open(mergeJDLName.Data(), ios::out);
1155 Error("CreateJDL", "Bad file name: %s", mergeJDLName.Data());
1158 out1 << sjdl1 << endl;
1161 // Copy jdl to grid workspace
1163 Info("CreateJDL", "\n##### You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1165 TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1166 TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1167 if (fProductionMode) {
1168 locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1169 locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1171 if (FileExists(locjdl)) gGrid->Rm(locjdl);
1172 if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1173 Info("CreateJDL", "\n##### Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1174 TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1176 Info("CreateJDL", "\n##### Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1177 TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1183 //______________________________________________________________________________
1184 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1186 // Returns true if file exists.
1187 if (!gGrid) return kFALSE;
1188 TGridResult *res = gGrid->Ls(lfn);
1189 if (!res) return kFALSE;
1190 TMap *map = dynamic_cast<TMap*>(res->At(0));
1195 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1196 if (!objs || !objs->GetString().Length()) {
1204 //______________________________________________________________________________
1205 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1207 // Returns true if directory exists. Can be also a path.
1208 if (!gGrid) return kFALSE;
1209 // Check if dirname is a path
1210 TString dirstripped = dirname;
1211 dirstripped = dirstripped.Strip();
1212 dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1213 TString dir = gSystem->BaseName(dirstripped);
1215 TString path = gSystem->DirName(dirstripped);
1216 TGridResult *res = gGrid->Ls(path, "-F");
1217 if (!res) return kFALSE;
1221 while ((map=dynamic_cast<TMap*>(next()))) {
1222 obj = map->GetValue("name");
1224 if (dir == obj->GetName()) {
1233 //______________________________________________________________________________
1234 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1236 // Check input data type.
1237 is_collection = kFALSE;
1241 Error("CheckDataType", "No connection to grid");
1244 is_collection = IsCollection(lfn);
1245 TString msg = "\n##### file: ";
1247 if (is_collection) {
1248 msg += " type: raw_collection;";
1249 // special treatment for collections
1251 // check for tag files in the collection
1252 TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1254 msg += " using_tags: No (unknown)";
1255 Info("CheckDataType", msg.Data());
1258 const char* typeStr = res->GetKey(0, "origLFN");
1259 if (!typeStr || !strlen(typeStr)) {
1260 msg += " using_tags: No (unknown)";
1261 Info("CheckDataType", msg.Data());
1264 TString file = typeStr;
1265 use_tags = file.Contains(".tag");
1266 if (use_tags) msg += " using_tags: Yes";
1267 else msg += " using_tags: No";
1268 Info("CheckDataType", msg.Data());
1273 is_xml = slfn.Contains(".xml");
1275 // Open xml collection and check if there are tag files inside
1276 msg += " type: xml_collection;";
1277 TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1279 msg += " using_tags: No (unknown)";
1280 Info("CheckDataType", msg.Data());
1283 TMap *map = coll->Next();
1285 msg += " using_tags: No (unknown)";
1286 Info("CheckDataType", msg.Data());
1289 map = (TMap*)map->GetValue("");
1291 if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1292 use_tags = file.Contains(".tag");
1294 if (use_tags) msg += " using_tags: Yes";
1295 else msg += " using_tags: No";
1296 Info("CheckDataType", msg.Data());
1299 use_tags = slfn.Contains(".tag");
1300 if (slfn.Contains(".root")) msg += " type: root file;";
1301 else msg += " type: unhnown file;";
1302 if (use_tags) msg += " using_tags: Yes";
1303 else msg += " using_tags: No";
1304 Info("CheckDataType", msg.Data());
1307 //______________________________________________________________________________
1308 void AliAnalysisAlien::EnablePackage(const char *package)
1310 // Enables a par file supposed to exist in the current directory.
1311 TString pkg(package);
1312 pkg.ReplaceAll(".par", "");
1314 if (gSystem->AccessPathName(pkg)) {
1315 Error("EnablePackage", "Package %s not found", pkg.Data());
1318 if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1319 Info("EnablePackage", "AliEn plugin will use .par packages");
1320 TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1322 fPackages = new TObjArray();
1323 fPackages->SetOwner();
1325 fPackages->Add(new TObjString(pkg));
1328 //______________________________________________________________________________
1329 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1331 // Get job status for all jobs with jobid>jobidstart.
1332 static char mstatus[20];
1338 TGridJobStatusList *list = gGrid->Ps("");
1339 if (!list) return mstatus;
1340 Int_t nentries = list->GetSize();
1341 TGridJobStatus *status;
1343 for (Int_t ijob=0; ijob<nentries; ijob++) {
1344 status = (TGridJobStatus *)list->At(ijob);
1345 pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1346 if (pid<jobidstart) continue;
1347 if (pid == lastid) {
1348 gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1350 switch (status->GetStatus()) {
1351 case TGridJobStatus::kWAITING:
1353 case TGridJobStatus::kRUNNING:
1355 case TGridJobStatus::kABORTED:
1356 case TGridJobStatus::kFAIL:
1357 case TGridJobStatus::kUNKNOWN:
1359 case TGridJobStatus::kDONE:
1368 //______________________________________________________________________________
1369 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1371 // Returns true if file is a collection. Functionality duplicated from
1372 // TAlien::Type() because we don't want to directly depend on TAlien.
1374 Error("IsCollection", "No connection to grid");
1377 TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1378 if (!res) return kFALSE;
1379 const char* typeStr = res->GetKey(0, "type");
1380 if (!typeStr || !strlen(typeStr)) return kFALSE;
1381 if (!strcmp(typeStr, "collection")) return kTRUE;
1386 //______________________________________________________________________________
1387 Bool_t AliAnalysisAlien::IsSingleOutput() const
1389 // Check if single-ouput option is on.
1390 return (!fOutputSingle.IsNull());
1393 //______________________________________________________________________________
1394 void AliAnalysisAlien::Print(Option_t *) const
1396 // Print current plugin settings.
1397 printf("### AliEn analysis plugin current settings ###\n");
1398 printf("= Production mode:______________________________ %d\n", fProductionMode);
1399 printf("= Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1400 printf("= Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1401 printf("= Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1403 printf("= User running the plugin: _____________________ %s\n", fUser.Data());
1404 printf("= Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1405 printf("= Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1406 printf("= Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1407 printf("= Data search pattern: _________________________ %s\n", fDataPattern.Data());
1408 printf("= Input data format: ___________________________ %s\n", fInputFormat.Data());
1409 if (fRunNumbers.Length())
1410 printf("= Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1412 printf("= Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1413 if (!fRunRange[0] && !fRunNumbers.Length()) {
1414 TIter next(fInputFiles);
1417 while ((obj=next())) list += obj->GetName();
1418 printf("= Input files to be processed: _________________ %s\n", list.Data());
1420 if (TestBit(AliAnalysisGrid::kTest))
1421 printf("= Number of input files used in test mode: _____ %d\n", fNtestFiles);
1422 printf("= List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1423 printf("= List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1424 printf("= List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1425 printf("=====================================================================\n");
1426 printf("= Job price: ___________________________________ %d\n", fPrice);
1427 printf("= Time to live (TTL): __________________________ %d\n", fTTL);
1428 printf("= Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1429 if (fMaxInitFailed>0)
1430 printf("= Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1431 if (fMasterResubmitThreshold>0)
1432 printf("= Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1433 if (fNrunsPerMaster>0)
1434 printf("= Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1435 printf("= Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1436 printf("= Name of the generated execution script: ______ %s\n", fExecutable.Data());
1437 printf("= Executable command: __________________________ %s\n", fExecutableCommand.Data());
1438 if (fArguments.Length())
1439 printf("= Arguments for the execution script: __________ %s\n",fArguments.Data());
1440 if (fExecutableArgs.Length())
1441 printf("= Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1442 printf("= Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1443 printf("= User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1444 printf("= Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1445 printf("= Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1447 printf("= Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1448 printf("= Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1449 if (fIncludePath.Data())
1450 printf("= Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1451 if (fCloseSE.Length())
1452 printf("= Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1453 if (fFriendChainName.Length())
1454 printf("= Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1456 TIter next(fPackages);
1459 while ((obj=next())) list += obj->GetName();
1460 printf("= Par files to be used: ________________________ %s\n", list.Data());
1464 //______________________________________________________________________________
1465 void AliAnalysisAlien::SetDefaults()
1467 // Set default values for everything. What cannot be filled will be left empty.
1468 if (fGridJDL) delete fGridJDL;
1469 fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1470 fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1473 fSplitMaxInputFileNumber = 100;
1475 fMasterResubmitThreshold = 0;
1479 fNrunsPerMaster = 1;
1480 fMaxMergeFiles = 100;
1482 fExecutable = "analysis.sh";
1483 fExecutableCommand = "root -b -q";
1485 fExecutableArgs = "";
1486 fAnalysisMacro = "myAnalysis.C";
1487 fAnalysisSource = "";
1488 fAdditionalLibs = "";
1492 fAliROOTVersion = "";
1493 fUser = ""; // Your alien user name
1494 fGridWorkingDir = "";
1495 fGridDataDir = ""; // Can be like: /alice/sim/PDC_08a/LHC08c9/
1496 fDataPattern = "*AliESDs.root"; // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1497 fFriendChainName = "";
1498 fGridOutputDir = "output";
1499 fOutputArchive = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1500 fOutputFiles = ""; // Like "AliAODs.root histos.root"
1501 fInputFormat = "xml-single";
1502 fJDLName = "analysis.jdl";
1503 fJobTag = "Automatically generated analysis JDL";
1504 fMergeExcludes = "";
1508 //______________________________________________________________________________
1509 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge)
1511 // Merge all registered outputs from basedir.
1512 TString output_file = output;
1514 TString output_chunk;
1515 TString previous_chunk = "";
1516 Int_t count_chunk = 0;
1517 Int_t count_zero = nmaxmerge;
1518 Bool_t merged = kTRUE;
1519 Int_t index = output_file.Index("@");
1520 if (index > 0) output_file.Remove(index);
1521 command = Form("find %s/ *%s", basedir, output_file.Data());
1522 printf("command: %s\n", command.Data());
1523 TGridResult *res = gGrid->Command(command);
1525 printf("Error: No result for the find command\n");
1529 TFileMerger *fm = 0;
1532 // Check if there is a merge operation to resume
1533 output_chunk = output_file;
1534 output_chunk.ReplaceAll(".root", "_*.root");
1535 // Check for existent temporary merge files
1536 if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1538 // Skip as many input files as in a chunk
1539 for (Int_t counter=0; counter<nmaxmerge; counter++) map = (TMap*)nextmap();
1541 ::Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1545 output_chunk = output_file;
1546 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1548 if (gSystem->AccessPathName(output_chunk)) continue;
1549 // Merged file with chunks up to <count_chunk> found
1550 printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1551 previous_chunk = output_chunk;
1555 count_zero = nmaxmerge;
1557 while ((map=(TMap*)nextmap())) {
1558 // Loop 'find' results and get next LFN
1559 if (count_zero == nmaxmerge) {
1560 // First file in chunk - create file merger and add previous chunk if any.
1561 fm = new TFileMerger(kFALSE);
1562 fm->SetFastMethod(kTRUE);
1563 if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1564 output_chunk = output_file;
1565 output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1567 // If last file found, put merged results in the output file
1568 if (map == res->Last()) output_chunk = output_file;
1569 TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1570 if (!objs || !objs->GetString().Length()) {
1571 // Nothing found - skip this output
1576 // Add file to be merged and decrement chunk counter.
1577 fm->AddFile(objs->GetString());
1579 if (count_zero==0 || map == res->Last()) {
1580 fm->OutputFile(output_chunk);
1581 if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1582 // Nothing found - skip this output
1583 ::Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1588 // Merge the outputs, then go to next chunk
1590 ::Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1596 ::Info("MergeOutputs", "\n##### Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1597 gSystem->Unlink(previous_chunk);
1599 if (map == res->Last()) {
1605 count_zero = nmaxmerge;
1606 previous_chunk = output_chunk;
1612 //______________________________________________________________________________
1613 Bool_t AliAnalysisAlien::MergeOutputs()
1615 // Merge analysis outputs existing in the AliEn space.
1616 if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1617 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1619 Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1622 if (fMergeViaJDL && !fProductionMode && TestBit(AliAnalysisGrid::kMerge)) {
1623 Info("MergeOutputs", "Submitting merging JDL");
1625 Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
1626 Info("MergeOutputs", "### Trying to continue merging ... (may fail if exited the shell prematurely)");
1628 // Get the output path
1629 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1630 if (!DirectoryExists(fGridOutputDir)) {
1631 Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1634 if (!fOutputFiles.Length()) {
1635 Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1638 // Check if fast read option was requested
1639 if (fFastReadOption) {
1640 Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !");
1641 gEnv->SetValue("XNet.ConnectTimeout",5);
1642 gEnv->SetValue("XNet.RequestTimeout",5);
1643 gEnv->SetValue("XNet.MaxRedirectCount",2);
1644 gEnv->SetValue("XNet.ReconnectTimeout",5);
1645 gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
1647 TObjArray *list = fOutputFiles.Tokenize(" ");
1650 TString output_file;
1651 Bool_t merged = kTRUE;
1652 while((str=(TObjString*)next())) {
1653 output_file = str->GetString();
1654 Int_t index = output_file.Index("@");
1655 if (index > 0) output_file.Remove(index);
1656 // Skip already merged outputs
1657 if (!gSystem->AccessPathName(output_file)) {
1658 Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1661 if (fMergeExcludes.Length() &&
1662 fMergeExcludes.Contains(output_file.Data())) continue;
1663 // Perform a 'find' command in the output directory, looking for registered outputs
1664 merged = MergeOutput(output_file, fGridOutputDir, fMaxMergeFiles);
1666 Error("MergeOutputs", "Terminate() will NOT be executed");
1673 //______________________________________________________________________________
1674 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1676 // Use the output files connected to output containers from the analysis manager
1677 // rather than the files defined by SetOutputFiles
1678 if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1679 Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1681 TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1684 //______________________________________________________________________________
1685 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1687 // Start remote grid analysis.
1689 // Check if output files have to be taken from the analysis manager
1690 if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1691 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1692 if (!mgr || !mgr->IsInitialized()) {
1693 Error("StartAnalysis", "You need an initialized analysis manager for this");
1697 TIter next(mgr->GetOutputs());
1698 AliAnalysisDataContainer *output;
1699 while ((output=(AliAnalysisDataContainer*)next())) {
1700 const char *filename = output->GetFileName();
1701 if (!(strcmp(filename, "default"))) {
1702 if (!mgr->GetOutputEventHandler()) continue;
1703 filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1705 if (fOutputFiles.Contains(filename)) continue;
1706 if (fOutputFiles.Length()) fOutputFiles += " ";
1707 fOutputFiles += filename;
1709 // Add extra files registered to the analysis manager
1710 if (mgr->GetExtraFiles().Length()) {
1711 if (fOutputFiles.Length()) fOutputFiles += " ";
1712 fOutputFiles += mgr->GetExtraFiles();
1715 // if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1716 if (TestBit(AliAnalysisGrid::kOffline)) {
1717 Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1718 \n there nor any job run. You can revise the JDL and analysis \
1719 \n macro then run the same in \"submit\" mode.");
1720 } else if (TestBit(AliAnalysisGrid::kTest)) {
1721 Info("StartAnalysis","\n##### LOCAL MODE ##### Your analysis will be run locally on a subset of the requested \
1723 } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1724 Info("StartAnalysis","\n##### SUBMIT MODE ##### Files required by your analysis are copied to your grid working \
1725 \n space and job submitted.");
1726 } else if (TestBit(AliAnalysisGrid::kMerge)) {
1727 Info("StartAnalysis","\n##### MERGE MODE ##### The registered outputs of the analysis will be merged");
1728 if (fMergeViaJDL) CheckInputData();
1731 Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");
1735 Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1739 if (!CheckInputData()) {
1740 Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1743 CreateDataset(fDataPattern);
1744 WriteAnalysisFile();
1745 WriteAnalysisMacro();
1747 WriteValidationScript();
1749 WriteMergingMacro();
1750 WriteMergeExecutable();
1751 WriteValidationScript(kTRUE);
1753 if (!CreateJDL()) return kFALSE;
1754 if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1755 if (TestBit(AliAnalysisGrid::kTest)) {
1756 // Locally testing the analysis
1757 Info("StartAnalysis", "\n_______________________________________________________________________ \
1758 \n Running analysis script in a daughter shell as on a worker node \
1759 \n_______________________________________________________________________");
1760 TObjArray *list = fOutputFiles.Tokenize(" ");
1763 TString output_file;
1764 while((str=(TObjString*)next())) {
1765 output_file = str->GetString();
1766 Int_t index = output_file.Index("@");
1767 if (index > 0) output_file.Remove(index);
1768 if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1771 gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1772 TString validationScript = fExecutable;
1773 validationScript.ReplaceAll(".sh", "_validation.sh");
1774 gSystem->Exec(Form("bash %s",validationScript.Data()));
1775 // gSystem->Exec("cat stdout");
1778 // Check if submitting is managed by LPM manager
1779 if (fProductionMode) {
1780 TString prodfile = fJDLName;
1781 prodfile.ReplaceAll(".jdl", ".prod");
1782 WriteProductionFile(prodfile);
1783 Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1786 // Submit AliEn job(s)
1787 gGrid->Cd(fGridOutputDir);
1790 if (!fRunNumbers.Length() && !fRunRange[0]) {
1791 // Submit a given xml or a set of runs
1792 res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1793 printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1795 const char *cjobId = res->GetKey(0,"jobId");
1797 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1800 Info("StartAnalysis", "\n_______________________________________________________________________ \
1801 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1802 \n_______________________________________________________________________",
1803 fJDLName.Data(), cjobId);
1809 // Submit for a range of enumeration of runs.
1813 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1814 \n You may exit at any time and terminate the job later using the option <terminate> \
1815 \n ##################################################################################", jobID.Data());
1816 gSystem->Exec("aliensh");
1820 //______________________________________________________________________________
1821 void AliAnalysisAlien::Submit()
1823 // Submit all master jobs.
1824 Int_t nmasterjobs = fInputFiles->GetEntries();
1825 Long_t tshoot = gSystem->Now();
1826 if (!fNsubmitted) SubmitNext();
1827 while (fNsubmitted < nmasterjobs) {
1828 Long_t now = gSystem->Now();
1829 if ((now-tshoot)>30000) {
1836 //______________________________________________________________________________
1837 void AliAnalysisAlien::SubmitMerging()
1839 // Submit all merging jobs.
1840 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1841 gGrid->Cd(fGridOutputDir);
1842 TString mergeJDLName = fExecutable;
1843 mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1844 Int_t ntosubmit = fInputFiles->GetEntries();
1845 printf("### Submitting %d merging jobs...\n", ntosubmit);
1846 for (Int_t i=0; i<ntosubmit; i++) {
1848 query = Form("submit %s %03d", mergeJDLName.Data(), i);
1849 printf("********* %s\n",query.Data());
1850 TGridResult *res = gGrid->Command(query);
1852 const char *cjobId = res->GetKey(0,"jobId");
1854 Error("StartAnalysis", "Your JDL %s could not be submitted", mergeJDLName.Data());
1857 Info("StartAnalysis", "\n_______________________________________________________________________ \
1858 \n##### Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1859 \n_______________________________________________________________________",
1860 mergeJDLName.Data(), cjobId);
1865 if (!ntosubmit) return;
1866 Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
1867 \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
1868 \n ##################################################################################");
1869 gSystem->Exec("aliensh");
1872 //______________________________________________________________________________
1873 void AliAnalysisAlien::SubmitNext()
1875 // Submit next bunch of master jobs if the queue is free.
1876 static Bool_t iscalled = kFALSE;
1877 static Int_t firstmaster = 0;
1878 static Int_t lastmaster = 0;
1879 static Int_t npermaster = 0;
1880 if (iscalled) return;
1882 Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1883 Int_t ntosubmit = 0;
1886 if (!fNsubmitted) ntosubmit = 1;
1888 TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1889 printf("=== master %d: %s\n", lastmaster, status.Data());
1890 // If last master not split, just return
1891 if (status != "SPLIT") {iscalled = kFALSE; return;}
1892 // No more than 100 waiting jobs
1893 if (nwaiting>100) {iscalled = kFALSE; return;}
1894 npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;
1895 if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1896 printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n",
1897 nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1899 Int_t nmasterjobs = fInputFiles->GetEntries();
1900 for (Int_t i=0; i<ntosubmit; i++) {
1901 // Submit for a range of enumeration of runs.
1902 if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1904 TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
1905 runOutDir.ReplaceAll(".xml", "");
1907 query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
1909 query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1910 printf("********* %s\n",query.Data());
1911 res = gGrid->Command(query);
1913 TString cjobId1 = res->GetKey(0,"jobId");
1914 if (!cjobId1.Length()) {
1915 Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1919 Info("StartAnalysis", "\n_______________________________________________________________________ \
1920 \n##### Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1921 \n_______________________________________________________________________",
1922 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1925 lastmaster = cjobId1.Atoi();
1926 if (!firstmaster) firstmaster = lastmaster;
1935 //______________________________________________________________________________
1936 void AliAnalysisAlien::WriteAnalysisFile()
1938 // Write current analysis manager into the file <analysisFile>
1939 TString analysisFile = fExecutable;
1940 analysisFile.ReplaceAll(".sh", ".root");
1941 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1942 AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1943 if (!mgr || !mgr->IsInitialized()) {
1944 Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1947 // Check analysis type
1949 if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1950 handler = (TObject*)mgr->GetInputEventHandler();
1952 if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1953 if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1955 TDirectory *cdir = gDirectory;
1956 TFile *file = TFile::Open(analysisFile, "RECREATE");
1958 // Skip task Terminate calls for the grid job
1959 mgr->SetSkipTerminate(kTRUE);
1960 // Unless merging makes no sense
1961 if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
1964 // Enable termination for local jobs
1965 mgr->SetSkipTerminate(kFALSE);
1967 if (cdir) cdir->cd();
1968 Info("WriteAnalysisFile", "\n##### Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1970 Bool_t copy = kTRUE;
1971 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1974 TString workdir = gGrid->GetHomeDirectory();
1975 workdir += fGridWorkingDir;
1976 Info("CreateJDL", "\n##### Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1977 if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1978 TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1982 //______________________________________________________________________________
1983 void AliAnalysisAlien::WriteAnalysisMacro()
1985 // Write the analysis macro that will steer the analysis in grid mode.
1986 if (!TestBit(AliAnalysisGrid::kSubmit)) {
1988 out.open(fAnalysisMacro.Data(), ios::out);
1990 Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1993 Bool_t hasSTEERBase = kFALSE;
1994 Bool_t hasESD = kFALSE;
1995 Bool_t hasAOD = kFALSE;
1996 Bool_t hasANALYSIS = kFALSE;
1997 Bool_t hasANALYSISalice = kFALSE;
1998 Bool_t hasCORRFW = kFALSE;
1999 TString func = fAnalysisMacro;
2000 TString type = "ESD";
2001 TString comment = "// Analysis using ";
2002 if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2003 if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2007 if (type!="AOD" && fFriendChainName!="") {
2008 Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2011 if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2012 else comment += " data";
2013 out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2014 func.ReplaceAll(".C", "");
2015 out << "void " << func.Data() << "()" << endl;
2017 out << comment.Data() << endl;
2018 out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2019 out << " TStopwatch timer;" << endl;
2020 out << " timer.Start();" << endl << endl;
2021 out << "// load base root libraries" << endl;
2022 out << " gSystem->Load(\"libTree\");" << endl;
2023 out << " gSystem->Load(\"libGeom\");" << endl;
2024 out << " gSystem->Load(\"libVMC\");" << endl;
2025 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
2026 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
2027 if (fAdditionalRootLibs.Length()) {
2028 // in principle libtree /lib geom libvmc etc. can go into this list, too
2029 out << "// Add aditional libraries" << endl;
2030 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2033 while((str=(TObjString*)next())) {
2034 if (str->GetString().Contains(".so"))
2035 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2037 if (list) delete list;
2039 out << "// include path" << endl;
2040 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2041 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2042 out << "// Load analysis framework libraries" << endl;
2044 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2045 out << " gSystem->Load(\"libESD\");" << endl;
2046 out << " gSystem->Load(\"libAOD\");" << endl;
2047 out << " gSystem->Load(\"libANALYSIS\");" << endl;
2048 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2049 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
2051 TIter next(fPackages);
2054 TString setupPar = "AliAnalysisAlien::SetupPar";
2055 while ((obj=next())) {
2056 pkgname = obj->GetName();
2057 if (pkgname == "STEERBase" ||
2058 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2059 if (pkgname == "ESD" ||
2060 pkgname == "ESD.par") hasESD = kTRUE;
2061 if (pkgname == "AOD" ||
2062 pkgname == "AOD.par") hasAOD = kTRUE;
2063 if (pkgname == "ANALYSIS" ||
2064 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
2065 if (pkgname == "ANALYSISalice" ||
2066 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2067 if (pkgname == "CORRFW" ||
2068 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
2070 if (hasANALYSISalice) setupPar = "SetupPar";
2071 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
2072 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2073 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
2074 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
2075 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
2076 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
2077 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
2078 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2079 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2080 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2081 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
2082 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2083 out << "// Compile other par packages" << endl;
2085 while ((obj=next())) {
2086 pkgname = obj->GetName();
2087 if (pkgname == "STEERBase" ||
2088 pkgname == "STEERBase.par" ||
2090 pkgname == "ESD.par" ||
2092 pkgname == "AOD.par" ||
2093 pkgname == "ANALYSIS" ||
2094 pkgname == "ANALYSIS.par" ||
2095 pkgname == "ANALYSISalice" ||
2096 pkgname == "ANALYSISalice.par" ||
2097 pkgname == "CORRFW" ||
2098 pkgname == "CORRFW.par") continue;
2099 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2102 if (fAdditionalLibs.Length()) {
2103 out << "// Add aditional AliRoot libraries" << endl;
2104 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2107 while((str=(TObjString*)next())) {
2108 if (str->GetString().Contains(".so"))
2109 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2111 if (list) delete list;
2114 out << "// analysis source to be compiled at runtime (if any)" << endl;
2115 if (fAnalysisSource.Length()) {
2116 TObjArray *list = fAnalysisSource.Tokenize(" ");
2119 while((str=(TObjString*)next())) {
2120 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2122 if (list) delete list;
2125 if (fFastReadOption) {
2126 Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. Note that this may skip some files that could be accessed !!!");
2127 out << "// fast xrootd reading enabled" << endl;
2128 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2129 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",5);" << endl;
2130 out << " gEnv->SetValue(\"XNet.RequestTimeout\",5);" << endl;
2131 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2132 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",5);" << endl;
2133 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2135 out << "// connect to AliEn and make the chain" << endl;
2136 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
2137 if (IsUsingTags()) {
2138 out << " TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2140 if(fFriendChainName!="AliAOD.VertexingHF.root") {
2141 out << " TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;
2143 out << " // Check if the macro to create the chain was provided" << endl;
2144 out << " if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
2145 out << " ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
2146 out << " return;" << endl;
2147 out << " }" << endl;
2148 out << " gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
2149 out << " TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
2152 out << "// read the analysis manager from file" << endl;
2153 TString analysisFile = fExecutable;
2154 analysisFile.ReplaceAll(".sh", ".root");
2155 out << " TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2156 out << " if (!file) return;" << endl;
2157 out << " TIter nextkey(file->GetListOfKeys());" << endl;
2158 out << " AliAnalysisManager *mgr = 0;" << endl;
2159 out << " TKey *key;" << endl;
2160 out << " while ((key=(TKey*)nextkey())) {" << endl;
2161 out << " if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2162 out << " mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2163 out << " };" << endl;
2164 out << " if (!mgr) {" << endl;
2165 out << " ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2166 out << " return;" << endl;
2167 out << " }" << endl << endl;
2168 out << " mgr->PrintStatus();" << endl;
2169 if (AliAnalysisManager::GetAnalysisManager()) {
2170 if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>2) {
2171 out << " gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2173 out << " AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2176 out << " mgr->StartAnalysis(\"localfile\", chain);" << endl;
2177 out << " timer.Stop();" << endl;
2178 out << " timer.Print();" << endl;
2179 out << "}" << endl << endl;
2180 if (IsUsingTags()) {
2181 out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2183 out << "// Create a chain using tags from the xml file." << endl;
2184 out << " TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2185 out << " if (!coll) {" << endl;
2186 out << " ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2187 out << " return NULL;" << endl;
2188 out << " }" << endl;
2189 out << " TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2190 out << " AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2191 out << " tagAna->ChainGridTags(tagResult);" << endl << endl;
2192 out << " AliRunTagCuts *runCuts = new AliRunTagCuts();" << endl;
2193 out << " AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();" << endl;
2194 out << " AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2195 out << " AliEventTagCuts *evCuts = new AliEventTagCuts();" << endl;
2196 out << " // Check if the cuts configuration file was provided" << endl;
2197 out << " if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2198 out << " gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2199 out << " ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2200 out << " }" << endl;
2201 if (fFriendChainName=="") {
2202 out << " TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2204 out << " TString tmpColl=\"tmpCollection.xml\";" << endl;
2205 out << " tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2206 out << " TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2208 out << " if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2209 out << " chain->ls();" << endl;
2210 out << " return chain;" << endl;
2211 out << "}" << endl << endl;
2212 if (gSystem->AccessPathName("ConfigureCuts.C")) {
2213 TString msg = "\n##### You may want to provide a macro ConfigureCuts.C with a method:\n";
2214 msg += " void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2215 msg += " AliLHCTagCuts *lhcCuts,\n";
2216 msg += " AliDetectorTagCuts *detCuts,\n";
2217 msg += " AliEventTagCuts *evCuts)";
2218 Info("WriteAnalysisMacro", msg.Data());
2221 if (!IsUsingTags() || fFriendChainName!="") {
2222 out <<"//________________________________________________________________________________" << endl;
2223 out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2225 out << "// Create a chain using url's from xml file" << endl;
2226 out << " TString treename = type;" << endl;
2227 out << " treename.ToLower();" << endl;
2228 out << " treename += \"Tree\";" << endl;
2229 out << " printf(\"***************************************\\n\");" << endl;
2230 out << " printf(\" Getting chain of trees %s\\n\", treename.Data());" << endl;
2231 out << " printf(\"***************************************\\n\");" << endl;
2232 out << " TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2233 out << " if (!coll) {" << endl;
2234 out << " ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2235 out << " return NULL;" << endl;
2236 out << " }" << endl;
2237 out << " TChain *chain = new TChain(treename);" << endl;
2238 if(fFriendChainName!="") {
2239 out << " TChain *chainFriend = new TChain(treename);" << endl;
2241 out << " coll->Reset();" << endl;
2242 out << " while (coll->Next()) {" << endl;
2243 out << " chain->Add(coll->GetTURL(\"\"));" << endl;
2244 if(fFriendChainName!="") {
2245 out << " TString fileFriend=coll->GetTURL(\"\");" << endl;
2246 out << " fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2247 out << " fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2248 out << " chainFriend->Add(fileFriend.Data());" << endl;
2250 out << " }" << endl;
2251 out << " if (!chain->GetNtrees()) {" << endl;
2252 out << " ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2253 out << " return NULL;" << endl;
2254 out << " }" << endl;
2255 if(fFriendChainName!="") {
2256 out << " chain->AddFriend(chainFriend);" << endl;
2258 out << " return chain;" << endl;
2259 out << "}" << endl << endl;
2261 if (hasANALYSISalice) {
2262 out <<"//________________________________________________________________________________" << endl;
2263 out << "Bool_t SetupPar(const char *package) {" << endl;
2264 out << "// Compile the package and set it up." << endl;
2265 out << " TString pkgdir = package;" << endl;
2266 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2267 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2268 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2269 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2270 out << " // Check for BUILD.sh and execute" << endl;
2271 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2272 out << " printf(\"*******************************\\n\");" << endl;
2273 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2274 out << " printf(\"*******************************\\n\");" << endl;
2275 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2276 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2277 out << " gSystem->ChangeDirectory(cdir);" << endl;
2278 out << " return kFALSE;" << endl;
2279 out << " }" << endl;
2280 out << " } else {" << endl;
2281 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2282 out << " gSystem->ChangeDirectory(cdir);" << endl;
2283 out << " return kFALSE;" << endl;
2284 out << " }" << endl;
2285 out << " // Check for SETUP.C and execute" << endl;
2286 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2287 out << " printf(\"*******************************\\n\");" << endl;
2288 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2289 out << " printf(\"*******************************\\n\");" << endl;
2290 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2291 out << " } else {" << endl;
2292 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2293 out << " gSystem->ChangeDirectory(cdir);" << endl;
2294 out << " return kFALSE;" << endl;
2295 out << " }" << endl;
2296 out << " // Restore original workdir" << endl;
2297 out << " gSystem->ChangeDirectory(cdir);" << endl;
2298 out << " return kTRUE;" << endl;
2301 Info("WriteAnalysisMacro", "\n##### Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2303 Bool_t copy = kTRUE;
2304 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2307 TString workdir = gGrid->GetHomeDirectory();
2308 workdir += fGridWorkingDir;
2309 if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2310 if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2311 if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2312 Info("WriteAnalysisMacro", "\n##### Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2313 TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2315 Info("WriteAnalysisMacro", "\n##### Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2316 TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2320 //______________________________________________________________________________
2321 void AliAnalysisAlien::WriteMergingMacro()
2323 // Write a macro to merge the outputs per master job.
2324 if (!fMergeViaJDL) return;
2325 if (!fOutputFiles.Length()) {
2326 Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2329 TString mergingMacro = fExecutable;
2330 mergingMacro.ReplaceAll(".sh","_merge.C");
2331 if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2332 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2334 out.open(mergingMacro.Data(), ios::out);
2336 Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2339 Bool_t hasSTEERBase = kFALSE;
2340 Bool_t hasESD = kFALSE;
2341 Bool_t hasAOD = kFALSE;
2342 Bool_t hasANALYSIS = kFALSE;
2343 Bool_t hasANALYSISalice = kFALSE;
2344 Bool_t hasCORRFW = kFALSE;
2345 TString func = mergingMacro;
2347 func.ReplaceAll(".C", "");
2348 out << "void " << func.Data() << "(const char *dir)" << endl;
2350 out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
2351 out << " TStopwatch timer;" << endl;
2352 out << " timer.Start();" << endl << endl;
2353 out << "// load base root libraries" << endl;
2354 out << " gSystem->Load(\"libTree\");" << endl;
2355 out << " gSystem->Load(\"libGeom\");" << endl;
2356 out << " gSystem->Load(\"libVMC\");" << endl;
2357 out << " gSystem->Load(\"libPhysics\");" << endl << endl;
2358 out << " gSystem->Load(\"libMinuit\");" << endl << endl;
2359 if (fAdditionalRootLibs.Length()) {
2360 // in principle libtree /lib geom libvmc etc. can go into this list, too
2361 out << "// Add aditional libraries" << endl;
2362 TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2365 while((str=(TObjString*)next())) {
2366 if (str->GetString().Contains(".so"))
2367 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2369 if (list) delete list;
2371 out << "// include path" << endl;
2372 if (fIncludePath.Length()) out << " gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2373 out << " gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2374 out << "// Load analysis framework libraries" << endl;
2376 out << " gSystem->Load(\"libSTEERBase\");" << endl;
2377 out << " gSystem->Load(\"libESD\");" << endl;
2378 out << " gSystem->Load(\"libAOD\");" << endl;
2379 out << " gSystem->Load(\"libANALYSIS\");" << endl;
2380 out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2381 out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
2383 TIter next(fPackages);
2386 TString setupPar = "AliAnalysisAlien::SetupPar";
2387 while ((obj=next())) {
2388 pkgname = obj->GetName();
2389 if (pkgname == "STEERBase" ||
2390 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2391 if (pkgname == "ESD" ||
2392 pkgname == "ESD.par") hasESD = kTRUE;
2393 if (pkgname == "AOD" ||
2394 pkgname == "AOD.par") hasAOD = kTRUE;
2395 if (pkgname == "ANALYSIS" ||
2396 pkgname == "ANALYSIS.par") hasANALYSIS = kTRUE;
2397 if (pkgname == "ANALYSISalice" ||
2398 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2399 if (pkgname == "CORRFW" ||
2400 pkgname == "CORRFW.par") hasCORRFW = kTRUE;
2402 if (hasANALYSISalice) setupPar = "SetupPar";
2403 if (!hasSTEERBase) out << " gSystem->Load(\"libSTEERBase\");" << endl;
2404 else out << " if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2405 if (!hasESD) out << " gSystem->Load(\"libESD\");" << endl;
2406 else out << " if (!" << setupPar << "(\"ESD\")) return;" << endl;
2407 if (!hasAOD) out << " gSystem->Load(\"libAOD\");" << endl;
2408 else out << " if (!" << setupPar << "(\"AOD\")) return;" << endl;
2409 if (!hasANALYSIS) out << " gSystem->Load(\"libANALYSIS\");" << endl;
2410 else out << " if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2411 if (!hasANALYSISalice) out << " gSystem->Load(\"libANALYSISalice\");" << endl;
2412 else out << " if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2413 if (!hasCORRFW) out << " gSystem->Load(\"libCORRFW\");" << endl << endl;
2414 else out << " if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2415 out << "// Compile other par packages" << endl;
2417 while ((obj=next())) {
2418 pkgname = obj->GetName();
2419 if (pkgname == "STEERBase" ||
2420 pkgname == "STEERBase.par" ||
2422 pkgname == "ESD.par" ||
2424 pkgname == "AOD.par" ||
2425 pkgname == "ANALYSIS" ||
2426 pkgname == "ANALYSIS.par" ||
2427 pkgname == "ANALYSISalice" ||
2428 pkgname == "ANALYSISalice.par" ||
2429 pkgname == "CORRFW" ||
2430 pkgname == "CORRFW.par") continue;
2431 out << " if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2434 if (fAdditionalLibs.Length()) {
2435 out << "// Add aditional AliRoot libraries" << endl;
2436 TObjArray *list = fAdditionalLibs.Tokenize(" ");
2439 while((str=(TObjString*)next())) {
2440 if (str->GetString().Contains(".so"))
2441 out << " gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2443 if (list) delete list;
2446 out << "// Analysis source to be compiled at runtime (if any)" << endl;
2447 if (fAnalysisSource.Length()) {
2448 TObjArray *list = fAnalysisSource.Tokenize(" ");
2451 while((str=(TObjString*)next())) {
2452 out << " gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2454 if (list) delete list;
2457 if (fFastReadOption) {
2458 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 !!!");
2459 out << "// fast xrootd reading enabled" << endl;
2460 out << " printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2461 out << " gEnv->SetValue(\"XNet.ConnectTimeout\",5);" << endl;
2462 out << " gEnv->SetValue(\"XNet.RequestTimeout\",5);" << endl;
2463 out << " gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2464 out << " gEnv->SetValue(\"XNet.ReconnectTimeout\",5);" << endl;
2465 out << " gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2467 out << "// Connect to AliEn" << endl;
2468 out << " if (!TGrid::Connect(\"alien://\")) return;" << endl;
2469 out << " TString outputDir = \"" << fGridOutputDir << "/\";" << endl;
2470 out << " outputDir += dir;" << endl;
2471 out << " TString outputFiles = \"" << fOutputFiles << "\";" << endl;
2472 out << " TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
2473 out << " TObjArray *list = outputFiles.Tokenize(\" \");" << endl;
2474 out << " TIter *iter = new TIter(list);" << endl;
2475 out << " TObjString *str;" << endl;
2476 out << " TString output_file;" << endl;
2477 out << " Bool_t merged = kTRUE;" << endl;
2478 out << " while((str=(TObjString*)iter->Next())) {" << endl;
2479 out << " output_file = str->GetString();" << endl;
2480 out << " Int_t index = output_file.Index(\"@\");" << endl;
2481 out << " if (index > 0) output_file.Remove(index);" << endl;
2482 out << " // Skip already merged outputs" << endl;
2483 out << " if (!gSystem->AccessPathName(output_file)) {" << endl;
2484 out << " printf(\"Output file <%s> found. Not merging again.\",output_file.Data());" << endl;
2485 out << " continue;" << endl;
2486 out << " }" << endl;
2487 out << " if (mergeExcludes.Contains(output_file.Data())) continue;" << endl;
2488 out << " merged = AliAnalysisAlien::MergeOutput(output_file, outputDir, " << fMaxMergeFiles << ");" << endl;
2489 out << " if (!merged) {" << endl;
2490 out << " printf(\"ERROR: Cannot merge %s\\n\", output_file.Data());" << endl;
2491 out << " return;" << endl;
2492 out << " }" << endl;
2493 out << " }" << endl;
2494 out << "}" << endl << endl;
2495 if (hasANALYSISalice) {
2496 out <<"//________________________________________________________________________________" << endl;
2497 out << "Bool_t SetupPar(const char *package) {" << endl;
2498 out << "// Compile the package and set it up." << endl;
2499 out << " TString pkgdir = package;" << endl;
2500 out << " pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2501 out << " gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2502 out << " TString cdir = gSystem->WorkingDirectory();" << endl;
2503 out << " gSystem->ChangeDirectory(pkgdir);" << endl;
2504 out << " // Check for BUILD.sh and execute" << endl;
2505 out << " if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2506 out << " printf(\"*******************************\\n\");" << endl;
2507 out << " printf(\"*** Building PAR archive ***\\n\");" << endl;
2508 out << " printf(\"*******************************\\n\");" << endl;
2509 out << " if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2510 out << " ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2511 out << " gSystem->ChangeDirectory(cdir);" << endl;
2512 out << " return kFALSE;" << endl;
2513 out << " }" << endl;
2514 out << " } else {" << endl;
2515 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2516 out << " gSystem->ChangeDirectory(cdir);" << endl;
2517 out << " return kFALSE;" << endl;
2518 out << " }" << endl;
2519 out << " // Check for SETUP.C and execute" << endl;
2520 out << " if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2521 out << " printf(\"*******************************\\n\");" << endl;
2522 out << " printf(\"*** Setup PAR archive ***\\n\");" << endl;
2523 out << " printf(\"*******************************\\n\");" << endl;
2524 out << " gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2525 out << " } else {" << endl;
2526 out << " ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2527 out << " gSystem->ChangeDirectory(cdir);" << endl;
2528 out << " return kFALSE;" << endl;
2529 out << " }" << endl;
2530 out << " // Restore original workdir" << endl;
2531 out << " gSystem->ChangeDirectory(cdir);" << endl;
2532 out << " return kTRUE;" << endl;
2536 Bool_t copy = kTRUE;
2537 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2540 TString workdir = gGrid->GetHomeDirectory();
2541 workdir += fGridWorkingDir;
2542 if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
2543 Info("WriteMergingMacro", "\n##### Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
2544 TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
2548 //______________________________________________________________________________
2549 Bool_t AliAnalysisAlien::SetupPar(const char *package)
2551 // Compile the par file archive pointed by <package>. This must be present in the current durectory.
2552 // Note that for loading the compiled library. The current directory should have precedence in
2554 TString pkgdir = package;
2555 pkgdir.ReplaceAll(".par","");
2556 gSystem->Exec(Form("tar xvzf %s.par", pkgdir.Data()));
2557 TString cdir = gSystem->WorkingDirectory();
2558 gSystem->ChangeDirectory(pkgdir);
2559 // Check for BUILD.sh and execute
2560 if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
2561 printf("**************************************************\n");
2562 printf("*** Building PAR archive %s\n", package);
2563 printf("**************************************************\n");
2564 if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
2565 ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
2566 gSystem->ChangeDirectory(cdir);
2570 ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
2571 gSystem->ChangeDirectory(cdir);
2574 // Check for SETUP.C and execute
2575 if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
2576 printf("**************************************************\n");
2577 printf("*** Setup PAR archive %s\n", package);
2578 printf("**************************************************\n");
2579 gROOT->Macro("PROOF-INF/SETUP.C");
2580 printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
2582 ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
2583 gSystem->ChangeDirectory(cdir);
2586 // Restore original workdir
2587 gSystem->ChangeDirectory(cdir);
2591 //______________________________________________________________________________
2592 void AliAnalysisAlien::WriteExecutable()
2594 // Generate the alien executable script.
2595 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2597 out.open(fExecutable.Data(), ios::out);
2599 Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2602 out << "#!/bin/bash" << endl;
2603 out << "echo \"=========================================\"" << endl;
2604 out << "echo \"############## PATH : ##############\"" << endl;
2605 out << "echo $PATH" << endl;
2606 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2607 out << "echo $LD_LIBRARY_PATH" << endl;
2608 out << "echo \"############## ROOTSYS : ##############\"" << endl;
2609 out << "echo $ROOTSYS" << endl;
2610 out << "echo \"############## which root : ##############\"" << endl;
2611 out << "which root" << endl;
2612 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2613 out << "echo $ALICE_ROOT" << endl;
2614 out << "echo \"############## which aliroot : ##############\"" << endl;
2615 out << "which aliroot" << endl;
2616 out << "echo \"############## system limits : ##############\"" << endl;
2617 out << "ulimit -a" << endl;
2618 out << "echo \"############## memory : ##############\"" << endl;
2619 out << "free -m" << endl;
2620 out << "echo \"=========================================\"" << endl << endl;
2621 // Make sure we can properly compile par files
2622 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2623 out << fExecutableCommand << " ";
2624 out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2625 out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2626 out << "echo \"############## memory after: ##############\"" << endl;
2627 out << "free -m" << endl;
2628 out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2629 out << "dmesg | tail -n 10" << endl;
2631 Bool_t copy = kTRUE;
2632 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2635 TString workdir = gGrid->GetHomeDirectory();
2636 TString bindir = Form("%s/bin", workdir.Data());
2637 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2638 workdir += fGridWorkingDir;
2639 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2640 if (FileExists(executable)) gGrid->Rm(executable);
2641 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2642 TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2646 //______________________________________________________________________________
2647 void AliAnalysisAlien::WriteMergeExecutable()
2649 // Generate the alien executable script for the merging job.
2650 if (!fMergeViaJDL) return;
2651 TString mergeExec = fExecutable;
2652 mergeExec.ReplaceAll(".sh", "_merge.sh");
2653 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2655 out.open(mergeExec.Data(), ios::out);
2657 Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
2660 out << "#!/bin/bash" << endl;
2661 out << "echo \"=========================================\"" << endl;
2662 out << "echo \"############## PATH : ##############\"" << endl;
2663 out << "echo $PATH" << endl;
2664 out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2665 out << "echo $LD_LIBRARY_PATH" << endl;
2666 out << "echo \"############## ROOTSYS : ##############\"" << endl;
2667 out << "echo $ROOTSYS" << endl;
2668 out << "echo \"############## which root : ##############\"" << endl;
2669 out << "which root" << endl;
2670 out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2671 out << "echo $ALICE_ROOT" << endl;
2672 out << "echo \"############## which aliroot : ##############\"" << endl;
2673 out << "which aliroot" << endl;
2674 out << "echo \"############## system limits : ##############\"" << endl;
2675 out << "ulimit -a" << endl;
2676 out << "echo \"############## memory : ##############\"" << endl;
2677 out << "free -m" << endl;
2678 out << "echo \"=========================================\"" << endl << endl;
2679 // Make sure we can properly compile par files
2680 if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2681 TString mergeMacro = fExecutable;
2682 mergeMacro.ReplaceAll(".sh", "_merge.C");
2683 out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
2684 out << fExecutableCommand << " " << "$ARG" << endl;
2685 out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
2686 out << "echo \"############## memory after: ##############\"" << endl;
2687 out << "free -m" << endl;
2688 out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2689 out << "dmesg | tail -n 10" << endl;
2691 Bool_t copy = kTRUE;
2692 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2695 TString workdir = gGrid->GetHomeDirectory();
2696 TString bindir = Form("%s/bin", workdir.Data());
2697 if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2698 workdir += fGridWorkingDir;
2699 TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
2700 if (FileExists(executable)) gGrid->Rm(executable);
2701 Info("CreateJDL", "\n##### Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
2702 TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
2706 //______________________________________________________________________________
2707 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2709 // Write the production file to be submitted by LPM manager. The format is:
2710 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2711 // Next lines: full_path_to_dataset XXX (XXX is a string)
2712 // To submit, one has to: submit jdl XXX for all lines
2714 out.open(filename, ios::out);
2716 Error("WriteProductionFile", "Bad file name: %s", filename);
2719 TString workdir = gGrid->GetHomeDirectory();
2720 workdir += fGridWorkingDir;
2721 Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2722 TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2723 out << locjdl << " " << njobspermaster << endl;
2724 Int_t nmasterjobs = fInputFiles->GetEntries();
2725 for (Int_t i=0; i<nmasterjobs; i++) {
2726 TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2727 runOutDir.ReplaceAll(".xml", "");
2729 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
2731 out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2733 Info("WriteProductionFile", "\n##### Copying production file <%s> to your work directory", filename);
2734 if (FileExists(filename)) gGrid->Rm(filename);
2735 TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
2738 //______________________________________________________________________________
2739 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
2741 // Generate the alien validation script.
2742 // Generate the validation script
2744 TString validationScript = fExecutable;
2745 if (merge) validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
2746 else validationScript.ReplaceAll(".sh", "_validation.sh");
2748 Error("WriteValidationScript", "Alien connection required");
2751 TString out_stream = "";
2752 if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2753 if (!TestBit(AliAnalysisGrid::kSubmit)) {
2755 out.open(validationScript, ios::out);
2756 out << "#!/bin/bash" << endl;
2757 out << "##################################################" << endl;
2758 out << "validateout=`dirname $0`" << endl;
2759 out << "validatetime=`date`" << endl;
2760 out << "validated=\"0\";" << endl;
2761 out << "error=0" << endl;
2762 out << "if [ -z $validateout ]" << endl;
2763 out << "then" << endl;
2764 out << " validateout=\".\"" << endl;
2765 out << "fi" << endl << endl;
2766 out << "cd $validateout;" << endl;
2767 out << "validateworkdir=`pwd`;" << endl << endl;
2768 out << "echo \"*******************************************************\"" << out_stream << endl;
2769 out << "echo \"* Automatically generated validation script *\"" << out_stream << endl;
2771 out << "echo \"* Time: $validatetime \"" << out_stream << endl;
2772 out << "echo \"* Dir: $validateout\"" << out_stream << endl;
2773 out << "echo \"* Workdir: $validateworkdir\"" << out_stream << endl;
2774 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2775 out << "ls -la ./" << out_stream << endl;
2776 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl << endl;
2777 out << "##################################################" << endl;
2780 out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2781 out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2782 out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2785 out << "if [ ! -f stderr ] ; then" << endl;
2786 out << " error=1" << endl;
2787 out << " echo \"* ########## Job not validated - no stderr ###\" " << out_stream << endl;
2788 out << " echo \"Error = $error\" " << out_stream << endl;
2789 out << "fi" << endl;
2791 out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2792 out << " error=1" << endl;
2793 out << " echo \"* ########## Job not validated - PAR archive not built ###\" " << out_stream << endl;
2794 out << " echo \"$parArch\" " << out_stream << endl;
2795 out << " echo \"Error = $error\" " << out_stream << endl;
2796 out << "fi" << endl;
2798 out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2799 out << " error=1" << endl;
2800 out << " echo \"* ########## Job not validated - Segment. violation ###\" " << out_stream << endl;
2801 out << " echo \"$segViol\" " << out_stream << endl;
2802 out << " echo \"Error = $error\" " << out_stream << endl;
2803 out << "fi" << endl;
2805 out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2806 out << " error=1" << endl;
2807 out << " echo \"* ########## Job not validated - Segment. fault ###\" " << out_stream << endl;
2808 out << " echo \"$segFault\" " << out_stream << endl;
2809 out << " echo \"Error = $error\" " << out_stream << endl;
2810 out << "fi" << endl;
2812 // Part dedicated to the specific analyses running into the train
2814 TObjArray *arr = fOutputFiles.Tokenize(" ");
2816 TString output_file;
2817 while ((os=(TObjString*)next1())) {
2818 output_file = os->GetString();
2819 Int_t index = output_file.Index("@");
2820 if (index > 0) output_file.Remove(index);
2821 if (merge && fMergeExcludes.Contains(output_file)) continue;
2822 out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2823 out << " error=1" << endl;
2824 out << " echo \"Output file(s) not found. Job FAILED !\"" << out_stream << endl;
2825 out << " echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2826 out << "fi" << endl;
2829 out << "if ! [ -f outputs_valid ] ; then" << endl;
2830 out << " error=1" << endl;
2831 out << " echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2832 out << " echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2833 out << "fi" << endl;
2835 out << "if [ $error = 0 ] ; then" << endl;
2836 out << " echo \"* ---------------- Job Validated ------------------*\"" << out_stream << endl;
2837 out << "fi" << endl;
2839 out << "echo \"* ----------------------------------------------------*\"" << out_stream << endl;
2840 out << "echo \"*******************************************************\"" << out_stream << endl;
2841 out << "cd -" << endl;
2842 out << "exit $error" << endl;
2844 Bool_t copy = kTRUE;
2845 if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2848 TString workdir = gGrid->GetHomeDirectory();
2849 workdir += fGridWorkingDir;
2850 Info("CreateJDL", "\n##### Copying validation script <%s> to your AliEn working space", validationScript.Data());
2851 if (FileExists(validationScript)) gGrid->Rm(validationScript);
2852 TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));