]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - ANALYSIS/AliAnalysisAlien.cxx
Array of bits introduced to control better the "atomic" operations of the plugin...
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisAlien.cxx
index 7df6508861151996c8c1bb7e8bc88cfe6543eb55..4370fcf087f778c8ff74728b4c5f7df96398a3ca 100644 (file)
@@ -358,11 +358,6 @@ Bool_t AliAnalysisAlien::Connect()
 {
 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
    if (gGrid && gGrid->IsConnected()) return kTRUE;
-   if (!gSystem->Getenv("alien_API_USER")) {
-      Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
-            gSystem->Getenv("UID"));
-      return kFALSE;
-   }         
    if (!gGrid) {
       Info("Connect", "Trying to connect to AliEn ...");
       TGrid::Connect("alien://");
@@ -402,6 +397,52 @@ void AliAnalysisAlien::CdWork()
    }          
 }
 
+//______________________________________________________________________________
+Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
+{
+// Check if file copying is possible.
+   if (!Connect()) {
+      Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
+      return kFALSE;
+   }
+   // Check if alien_CLOSE_SE is defined
+   TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
+   if (!closeSE.IsNull()) {
+      Info("CheckFileCopy", "Your current close storage is pointing to: \
+           \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
+   } else {
+      Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
+   }        
+   // Check if grid directory exists.
+   if (!DirectoryExists(alienpath)) {
+      Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
+      return kFALSE;
+   }
+   TFile f("plugin_test_copy.root", "RECREATE");
+   // User may not have write permissions to current directory 
+   if (f.IsZombie()) {
+      Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
+            gSystem->WorkingDirectory());
+      return kFALSE;
+   }
+   f.Close();
+   TString s = f.GetUUID().AsString();
+   s.ReplaceAll("-",""); // AliEn copy does not like too many '-'
+   if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, s.Data()))) {
+      Error("CheckFileCopy", "Cannot copy files to Alien destination: %s \
+           \n# 1. Make sure you have write permissions there. If this is the case: \
+           \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
+           \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
+           \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
+           \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
+      gSystem->Unlink(f.GetName());
+      return kFALSE;
+   }   
+   gSystem->Unlink(f.GetName());
+   gGrid->Rm(Form("%s%s",alienpath,s.Data()));
+   return kTRUE;
+}   
+
 //______________________________________________________________________________
 Bool_t AliAnalysisAlien::CheckInputData()
 {
@@ -848,9 +889,12 @@ Bool_t AliAnalysisAlien::CreateJDL()
       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
       if (!fArguments.IsNull())
          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
-      fMergingJDL->SetArguments("$1");   
-      fGridJDL->SetTTL((UInt_t)fTTL);
-      fMergingJDL->SetTTL((UInt_t)fTTL);
+      fMergingJDL->SetArguments("$1"); 
+      fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
+      fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
+      fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
+      fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
+        
       if (fMaxInitFailed > 0) {
          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
@@ -894,6 +938,7 @@ Bool_t AliAnalysisAlien::CreateJDL()
       TString analysisFile = fExecutable;
       analysisFile.ReplaceAll(".sh", ".root");
       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
+      fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
       if (fAdditionalLibs.Length()) {
@@ -1298,7 +1343,7 @@ void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Boo
    }
    use_tags = slfn.Contains(".tag");
    if (slfn.Contains(".root")) msg += " type: root file;";
-   else                        msg += " type: unhnown file;";
+   else                        msg += " type: unknown file;";
    if (use_tags) msg += " using_tags: Yes";
    else          msg += " using_tags: No";
    Info("CheckDataType", msg.Data());
@@ -1312,7 +1357,7 @@ void AliAnalysisAlien::EnablePackage(const char *package)
    pkg.ReplaceAll(".par", "");
    pkg += ".par";
    if (gSystem->AccessPathName(pkg)) {
-      Error("EnablePackage", "Package %s not found", pkg.Data());
+      Fatal("EnablePackage", "Package %s not found", pkg.Data());
       return;
    }
    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
@@ -1395,6 +1440,8 @@ void AliAnalysisAlien::Print(Option_t *) const
 {
 // Print current plugin settings.
    printf("### AliEn analysis plugin current settings ###\n");
+   printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
+   printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
    printf("=   Production mode:______________________________ %d\n", fProductionMode);
    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
@@ -1503,6 +1550,8 @@ void AliAnalysisAlien::SetDefaults()
    fJobTag                     = "Automatically generated analysis JDL";
    fMergeExcludes              = "";
    fMergeViaJDL                = 0;
+   SetUseCopy(kTRUE);
+   SetCheckCopy(kTRUE);
 }   
 
 //______________________________________________________________________________
@@ -1619,11 +1668,20 @@ Bool_t AliAnalysisAlien::MergeOutputs()
       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
       return kFALSE;
    }
-   if (fMergeViaJDL && !fProductionMode && TestBit(AliAnalysisGrid::kMerge)) {
+   if (fMergeViaJDL) {
+      if (!TestBit(AliAnalysisGrid::kMerge)) {
+         Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
+         return kFALSE; 
+      }     
+      if (fProductionMode) {
+         Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
+         return kFALSE;
+      }
       Info("MergeOutputs", "Submitting merging JDL");
-      SubmitMerging();
+      if (!SubmitMerging()) return kFALSE;
       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
-      Info("MergeOutputs", "### Trying to continue merging ... (may fail if exited the shell prematurely)");
+      Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
+      return kFALSE;
    }   
    // Get the output path
    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
@@ -1731,11 +1789,12 @@ Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEn
       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
    }   
       
+   Print();   
    if (!Connect()) {
       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
       return kFALSE;
    }
-   Print();   
+   if (IsCheckCopy()) CheckFileCopy(gGrid->GetHomeDirectory());
    if (!CheckInputData()) {
       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
       return kFALSE;
@@ -1794,6 +1853,8 @@ Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEn
       if (res) {
          const char *cjobId = res->GetKey(0,"jobId");
          if (!cjobId) {
+            gGrid->Stdout();
+            gGrid->Stderr();
             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
             return kFALSE;
          } else {
@@ -1804,10 +1865,13 @@ Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEn
             jobID = cjobId;      
          }          
          delete res;
+      } else {
+         Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
+         return kFALSE;      
       }   
    } else {
       // Submit for a range of enumeration of runs.
-      Submit();
+      if (!Submit()) return kFALSE;
    }   
          
    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
@@ -1818,23 +1882,24 @@ Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEn
 }
 
 //______________________________________________________________________________
-void AliAnalysisAlien::Submit()
+Bool_t AliAnalysisAlien::Submit()
 {
 // Submit all master jobs.
    Int_t nmasterjobs = fInputFiles->GetEntries();
    Long_t tshoot = gSystem->Now();
-   if (!fNsubmitted) SubmitNext();
+   if (!fNsubmitted && !SubmitNext()) return kFALSE;
    while (fNsubmitted < nmasterjobs) {
       Long_t now = gSystem->Now();
       if ((now-tshoot)>30000) {
          tshoot = now;
-         SubmitNext();
+         if (!SubmitNext()) return kFALSE;
       }   
    }
+   return kTRUE;
 }
 
 //______________________________________________________________________________
-void AliAnalysisAlien::SubmitMerging()
+Bool_t AliAnalysisAlien::SubmitMerging()
 {
 // Submit all merging jobs.
    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
@@ -1845,14 +1910,21 @@ void AliAnalysisAlien::SubmitMerging()
    printf("### Submitting %d merging jobs...\n", ntosubmit);
    for (Int_t i=0; i<ntosubmit; i++) {
       TString query;
-      query = Form("submit %s %03d", mergeJDLName.Data(), i);
+      TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
+      runOutDir.ReplaceAll(".xml", "");
+      if (fOutputToRunNo)
+         query = Form("submit %s %s", mergeJDLName.Data(), runOutDir.Data());
+      else
+         query = Form("submit %s %03d", mergeJDLName.Data(), i);
       printf("********* %s\n",query.Data());
       TGridResult *res = gGrid->Command(query);
       if (res) {
          const char *cjobId = res->GetKey(0,"jobId");
          if (!cjobId) {
+            gGrid->Stdout();
+            gGrid->Stderr();
             Error("StartAnalysis", "Your JDL %s could not be submitted", mergeJDLName.Data());
-            return;
+            return kFALSE;
          } else {
             Info("StartAnalysis", "\n_______________________________________________________________________ \
             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
@@ -1860,24 +1932,28 @@ void AliAnalysisAlien::SubmitMerging()
                    mergeJDLName.Data(), cjobId);
          }
          delete res;
+      } else {     
+         Error("SubmitMerging", "No grid result after submission !!! Bailing out...");
+         return kFALSE;
       }             
    }
-   if (!ntosubmit) return;
+   if (!ntosubmit) return kTRUE;
    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
    \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
    \n ##################################################################################");
    gSystem->Exec("aliensh");
+   return kTRUE;
 }
 
 //______________________________________________________________________________
-void AliAnalysisAlien::SubmitNext()
+Bool_t AliAnalysisAlien::SubmitNext()
 {
 // Submit next bunch of master jobs if the queue is free.
    static Bool_t iscalled = kFALSE;
    static Int_t firstmaster = 0;
    static Int_t lastmaster = 0;
    static Int_t npermaster  = 0;
-   if (iscalled) return;
+   if (iscalled) return kTRUE;
    iscalled = kTRUE;
    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
    Int_t ntosubmit = 0;
@@ -1888,18 +1964,19 @@ void AliAnalysisAlien::SubmitNext()
       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
       printf("=== master %d: %s\n", lastmaster, status.Data());
       // If last master not split, just return
-      if (status != "SPLIT") {iscalled = kFALSE; return;}
+      if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
       // No more than 100 waiting jobs
-      if (nwaiting>100) {iscalled = kFALSE; return;}
+      if (nwaiting>100) {iscalled = kFALSE; return kTRUE;}
       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
+      if (!ntosubmit) ntosubmit = 1;
       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
    }
    Int_t nmasterjobs = fInputFiles->GetEntries();
    for (Int_t i=0; i<ntosubmit; i++) {
       // Submit for a range of enumeration of runs.
-      if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
+      if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
       TString query;
       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
       runOutDir.ReplaceAll(".xml", "");
@@ -1912,9 +1989,11 @@ void AliAnalysisAlien::SubmitNext()
       if (res) {
          TString cjobId1 = res->GetKey(0,"jobId");
          if (!cjobId1.Length()) {
-            Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
             iscalled = kFALSE;
-            return;
+            gGrid->Stdout();
+            gGrid->Stderr();
+            Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
+            return kFALSE;
          } else {
             Info("StartAnalysis", "\n_______________________________________________________________________ \
             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
@@ -1927,9 +2006,13 @@ void AliAnalysisAlien::SubmitNext()
             fNsubmitted++;
          }          
          delete res;
+      } else {
+         Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
+         return kFALSE;
       }   
    }
    iscalled = kFALSE;
+   return kTRUE;
 }
 
 //______________________________________________________________________________
@@ -1990,6 +2073,12 @@ void AliAnalysisAlien::WriteAnalysisMacro()
          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
          return;
       }
+      Bool_t hasSTEERBase = kFALSE;
+      Bool_t hasESD = kFALSE;
+      Bool_t hasAOD = kFALSE;
+      Bool_t hasANALYSIS = kFALSE;
+      Bool_t hasANALYSISalice = kFALSE;
+      Bool_t hasCORRFW = kFALSE;
       TString func = fAnalysisMacro;
       TString type = "ESD";
       TString comment = "// Analysis using ";
@@ -2045,12 +2134,7 @@ void AliAnalysisAlien::WriteAnalysisMacro()
          TIter next(fPackages);
          TObject *obj;
          TString pkgname;
-         Bool_t hasSTEERBase = kFALSE;
-         Bool_t hasESD = kFALSE;
-         Bool_t hasAOD = kFALSE;
-         Bool_t hasANALYSIS = kFALSE;
-         Bool_t hasANALYSISalice = kFALSE;
-         Bool_t hasCORRFW = kFALSE;
+         TString setupPar = "AliAnalysisAlien::SetupPar";
          while ((obj=next())) {
             pkgname = obj->GetName();
             if (pkgname == "STEERBase" ||
@@ -2065,19 +2149,20 @@ void AliAnalysisAlien::WriteAnalysisMacro()
                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
             if (pkgname == "CORRFW" ||
                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
-         }   
+         }
+         if (hasANALYSISalice) setupPar = "SetupPar";   
          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"STEERBase\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"ESD\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"AOD\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"ANALYSIS\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"ANALYSISalice\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"CORRFW\")) return;" << endl << endl;
+         else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
          out << "// Compile other par packages" << endl;
          next.Reset();
          while ((obj=next())) {
@@ -2094,7 +2179,7 @@ void AliAnalysisAlien::WriteAnalysisMacro()
                 pkgname == "ANALYSISalice.par" ||
                 pkgname == "CORRFW" ||
                 pkgname == "CORRFW.par") continue;
-            out << "   if (!AliAnalysisAlien::SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
+            out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
          }   
       }   
       if (fAdditionalLibs.Length()) {
@@ -2165,7 +2250,7 @@ void AliAnalysisAlien::WriteAnalysisMacro()
       out << "   }" << endl << endl;
       out << "   mgr->PrintStatus();" << endl;
       if (AliAnalysisManager::GetAnalysisManager()) {
-         if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>2) {
+         if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
          } else {
             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
@@ -2256,6 +2341,46 @@ void AliAnalysisAlien::WriteAnalysisMacro()
          out << "   return chain;" << endl;
          out << "}" << endl << endl;
       }   
+      if (hasANALYSISalice) {
+         out <<"//________________________________________________________________________________" << endl;
+         out << "Bool_t SetupPar(const char *package) {" << endl;
+         out << "// Compile the package and set it up." << endl;
+         out << "   TString pkgdir = package;" << endl;
+         out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
+         out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
+         out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
+         out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
+         out << "   // Check for BUILD.sh and execute" << endl;
+         out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
+         out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
+         out << "         gSystem->ChangeDirectory(cdir);" << endl;
+         out << "         return kFALSE;" << endl;
+         out << "      }" << endl;
+         out << "   } else {" << endl;
+         out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
+         out << "      gSystem->ChangeDirectory(cdir);" << endl;
+         out << "      return kFALSE;" << endl;
+         out << "   }" << endl;
+         out << "   // Check for SETUP.C and execute" << endl;
+         out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
+         out << "   } else {" << endl;
+         out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
+         out << "      gSystem->ChangeDirectory(cdir);" << endl;
+         out << "      return kFALSE;" << endl;
+         out << "   }" << endl;
+         out << "   // Restore original workdir" << endl;
+         out << "   gSystem->ChangeDirectory(cdir);" << endl;
+         out << "   return kTRUE;" << endl;
+         out << "}" << endl;
+      }
       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
    }   
    Bool_t copy = kTRUE;
@@ -2294,6 +2419,12 @@ void AliAnalysisAlien::WriteMergingMacro()
          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
          return;
       }
+      Bool_t hasSTEERBase = kFALSE;
+      Bool_t hasESD = kFALSE;
+      Bool_t hasAOD = kFALSE;
+      Bool_t hasANALYSIS = kFALSE;
+      Bool_t hasANALYSISalice = kFALSE;
+      Bool_t hasCORRFW = kFALSE;
       TString func = mergingMacro;
       TString comment;
       func.ReplaceAll(".C", "");
@@ -2335,12 +2466,7 @@ void AliAnalysisAlien::WriteMergingMacro()
          TIter next(fPackages);
          TObject *obj;
          TString pkgname;
-         Bool_t hasSTEERBase = kFALSE;
-         Bool_t hasESD = kFALSE;
-         Bool_t hasAOD = kFALSE;
-         Bool_t hasANALYSIS = kFALSE;
-         Bool_t hasANALYSISalice = kFALSE;
-         Bool_t hasCORRFW = kFALSE;
+         TString setupPar = "AliAnalysisAlien::SetupPar";
          while ((obj=next())) {
             pkgname = obj->GetName();
             if (pkgname == "STEERBase" ||
@@ -2356,18 +2482,19 @@ void AliAnalysisAlien::WriteMergingMacro()
             if (pkgname == "CORRFW" ||
                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
          }   
+         if (hasANALYSISalice) setupPar = "SetupPar";   
          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"STEERBase\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"ESD\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"AOD\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"ANALYSIS\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"ANALYSISalice\")) return;" << endl;
+         else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
-         else out << "   if (!AliAnalysisAlien::SetupPar(\"CORRFW\")) return;" << endl << endl;
+         else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
          out << "// Compile other par packages" << endl;
          next.Reset();
          while ((obj=next())) {
@@ -2384,7 +2511,7 @@ void AliAnalysisAlien::WriteMergingMacro()
                 pkgname == "ANALYSISalice.par" ||
                 pkgname == "CORRFW" ||
                 pkgname == "CORRFW.par") continue;
-            out << "   if (!AliAnalysisAlien::SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
+            out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
          }   
       }   
       if (fAdditionalLibs.Length()) {
@@ -2426,6 +2553,7 @@ void AliAnalysisAlien::WriteMergingMacro()
       out << "   outputDir += dir;" << endl;    
       out << "   TString outputFiles = \"" << fOutputFiles << "\";" << endl;
       out << "   TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
+      out << "   mergeExcludes += \"" << AliAnalysisManager::GetAnalysisManager()->GetExtraFiles() << "\";" << endl;
       out << "   TObjArray *list = outputFiles.Tokenize(\" \");" << endl;
       out << "   TIter *iter = new TIter(list);" << endl;
       out << "   TObjString *str;" << endl;
@@ -2444,10 +2572,75 @@ void AliAnalysisAlien::WriteMergingMacro()
       out << "      merged = AliAnalysisAlien::MergeOutput(output_file, outputDir, " << fMaxMergeFiles << ");" << endl;
       out << "      if (!merged) {" << endl;
       out << "         printf(\"ERROR: Cannot merge %s\\n\", output_file.Data());" << endl;
-      out << "         return;" << endl;
       out << "      }" << endl;
       out << "   }" << endl;
+      out << "// read the analysis manager from file" << endl;
+      TString analysisFile = fExecutable;
+      analysisFile.ReplaceAll(".sh", ".root");
+      out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
+      out << "   if (!file) return;" << endl; 
+      out << "   TIter nextkey(file->GetListOfKeys());" << endl;
+      out << "   AliAnalysisManager *mgr = 0;" << endl;
+      out << "   TKey *key;" << endl;
+      out << "   while ((key=(TKey*)nextkey())) {" << endl;
+      out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
+      out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
+      out << "   };" << endl;
+      out << "   if (!mgr) {" << endl;
+      out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
+      out << "      return;" << endl;
+      out << "   }" << endl << endl;
+      out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
+      out << "   mgr->PrintStatus();" << endl;
+      if (AliAnalysisManager::GetAnalysisManager()) {
+         if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
+            out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
+         } else {
+            out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
+         }
+      }   
+      out << "   mgr->StartAnalysis(\"gridterminate\");" << endl;
       out << "}" << endl << endl;
+      if (hasANALYSISalice) {
+         out <<"//________________________________________________________________________________" << endl;
+         out << "Bool_t SetupPar(const char *package) {" << endl;
+         out << "// Compile the package and set it up." << endl;
+         out << "   TString pkgdir = package;" << endl;
+         out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
+         out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
+         out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
+         out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
+         out << "   // Check for BUILD.sh and execute" << endl;
+         out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
+         out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
+         out << "         gSystem->ChangeDirectory(cdir);" << endl;
+         out << "         return kFALSE;" << endl;
+         out << "      }" << endl;
+         out << "   } else {" << endl;
+         out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
+         out << "      gSystem->ChangeDirectory(cdir);" << endl;
+         out << "      return kFALSE;" << endl;
+         out << "   }" << endl;
+         out << "   // Check for SETUP.C and execute" << endl;
+         out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
+         out << "      printf(\"*******************************\\n\");" << endl;
+         out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
+         out << "   } else {" << endl;
+         out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
+         out << "      gSystem->ChangeDirectory(cdir);" << endl;
+         out << "      return kFALSE;" << endl;
+         out << "   }" << endl;
+         out << "   // Restore original workdir" << endl;
+         out << "   gSystem->ChangeDirectory(cdir);" << endl;
+         out << "   return kTRUE;" << endl;
+         out << "}" << endl;
+      }
    }   
    Bool_t copy = kTRUE;
    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
@@ -2730,11 +2923,14 @@ void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
       TObjArray *arr = fOutputFiles.Tokenize(" ");
       TIter next1(arr);
       TString output_file;
+      AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
+      TString extra = mgr->GetExtraFiles();
       while ((os=(TObjString*)next1())) { 
          output_file = os->GetString();
          Int_t index = output_file.Index("@");
          if (index > 0) output_file.Remove(index);
          if (merge && fMergeExcludes.Contains(output_file)) continue;
+         if (extra.Contains(output_file)) continue;
          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
          out << "   error=1" << endl;
          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
@@ -2742,11 +2938,13 @@ void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
          out << "fi" << endl;
       }   
       delete arr;
-      out << "if ! [ -f outputs_valid ] ; then" << endl;
-      out << "   error=1" << endl;
-      out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
-      out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
-      out << "fi" << endl;
+      if (!merge) {
+        out << "if ! [ -f outputs_valid ] ; then" << endl;
+        out << "   error=1" << endl;
+        out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
+        out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
+        out << "fi" << endl;
+      }  
       
       out << "if [ $error = 0 ] ; then" << endl;
       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;