/************************************************************************** * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * * * * Author: The ALICE Off-line Project. * * Contributors are mentioned in the code where appropriate. * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ // // AliMuonGridSubmitter : a class to help submit jobs for several runs // // This class is dealing with 3 different directories : // // - template directory ($ALICE_ROOT/PWG/muondep/XXXTemplates) containing the // basic template files to be used for a particular job type (XXX). A template can contain // some variables that will be replaced during during the copy from template // to local dir // // - local directory, where the files from the template directory, are copied // once the class has been configured properly (i.e. using the various Set, Use, // etc... methods). Some other files (e.g. JDL ones) are generated from // scratch and also copied into this directory. // At this point one could(should) check the files, as they are the ones // to be copied to the remote directory for the production // // - remote directory, the alien directory where the files will be copied // (from the local directory) before the actual submission // // author: Laurent Aphecetche (Subatech // #include "AliMuonGridSubmitter.h" #include "AliLog.h" #include "TFile.h" #include "TGrid.h" #include "TGridResult.h" #include "TMap.h" #include "TMath.h" #include "TObjString.h" #include "TROOT.h" #include "TString.h" #include "TSystem.h" #include #include "AliAnalysisTriggerScalers.h" #include "Riostream.h" //______________________________________________________________________________ AliMuonGridSubmitter::AliMuonGridSubmitter(AliMuonGridSubmitter::EJobType jobType, Bool_t localOnly) : TObject(), fInternalMap(0x0), fVars(0x0), fIsValid(kFALSE), fShouldOverwriteFiles(kFALSE), fTemplateFileList(0x0), fLocalFileList(0x0), fRunList() { // ctor if (!gGrid && !localOnly) { TGrid::Connect("alien://"); if ( !gGrid ) { AliError("cannot connect to grid"); } } SetPackages("VO_ALICE@AliRoot::v5-04-Rev-18","VO_ALICE@ROOT::v5-34-08-5","VO_ALICE@GEANT3::v1-15a-1"); TString basedir = gSystem->ExpandPathName("$ALICE_ROOT/PWG/muondep"); TString dir; dir.Form("%s/%sTemplates",basedir.Data(),JobTypeName(jobType).Data()); if (!SetTemplateDir(dir.Data())) { AliError(Form("Could not find %s directory. Please check.",dir.Data())); } SetLocalDir(gSystem->pwd()); } //______________________________________________________________________________ AliMuonGridSubmitter::~AliMuonGridSubmitter() { // dtor delete fTemplateFileList; delete fLocalFileList; delete fInternalMap; delete fVars; } ///______________________________________________________________________________ void AliMuonGridSubmitter::AddIncludePath(const char* pathList) const { TObjArray* paths = TString(pathList).Tokenize(" "); TIter next(paths); TObjString* p; TString includePath = gSystem->GetIncludePath(); while ( ( p = static_cast(next()) ) ) { if ( !includePath.Contains(p->String()) ) { gSystem->AddIncludePath(p->String().Data()); } } delete paths; } //______________________________________________________________________________ void AliMuonGridSubmitter::AddToTemplateFileList(const char* filename) { // add a file to the list of templates // and update the local file list if needed TObjArray* a = TemplateFileList(); if ( !a->FindObject(filename) ) { a->Add(new TObjString(filename)); UpdateLocalFileList(); } } //______________________________________________________________________________ void AliMuonGridSubmitter::AddToLocalFileList(const char* filename) { // add a file to the list of local files TObjArray* a = LocalFileList(); if ( !a->FindObject(filename) ) { a->Add(new TObjString(filename)); } } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CheckCompilation(const char* file) const { /// Check whether file can be compiled or not /// FIXME: use gSystem->TempFileName for tmpfile ! Bool_t rv(kTRUE); TString sfile(gSystem->BaseName(file)); TString tmpfile(Form("tmpfile_%s",sfile.Data())); gSystem->Exec(Form("cp %s %s",file,tmpfile.Data())); ReplaceVars(tmpfile.Data()); gSystem->AddIncludePath("-I$ALICE_ROOT/include"); gSystem->AddIncludePath("-I$ALICE_ROOT/EVGEN"); if (gROOT->LoadMacro(Form("%s++",tmpfile.Data()))) { AliError(Form("macro %s can not be compiled. Please check.",file)); rv = kFALSE; } gSystem->Exec(Form("rm %s",tmpfile.Data())); return rv; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CheckLocal() const { /// Check whether all required local files are there TIter next(LocalFileList()); TObjString* file; while ( ( file = static_cast(next())) ) { if ( gSystem->AccessPathName(file->String().Data()) ) { return kFALSE; } } return kTRUE; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CheckRemote() const { /// Check whether all required remote files are there AliWarning("implement me"); return kFALSE; } //______________________________________________________________________________ void AliMuonGridSubmitter::CleanLocal(const char* excludeList) const { /// Clean (remove) local generated files /// exclude contains a list of comma separated pattern of files /// to be avoided TIter next(LocalFileList()); TObjString* file; TObjArray* excludeArray = TString(excludeList).Tokenize(","); while ( ( file = static_cast(next())) ) { Bool_t shouldExclude(kFALSE); TIter nextExclude(excludeArray); TObjString* s; while ( ( s = static_cast(nextExclude())) && !shouldExclude ) { if ( file->String().Contains(s->String()) ) shouldExclude=kTRUE; } if (!shouldExclude) { gSystem->Unlink(file->String().Data()); } } delete excludeArray; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CopyFile(const char* localFile) { /// copy a local file to remote destination TString local; if ( gSystem->IsAbsoluteFileName(localFile) ) { local = localFile; } else { local = Form("%s/%s",LocalDir().Data(),gSystem->ExpandPathName(localFile)); } if (gSystem->AccessPathName(local.Data())) { AliErrorClass(Form("Local file %s does not exist",local.Data())); return kFALSE; } TString remote; remote += RemoteDir().Data(); remote += "/"; if ( gSystem->IsAbsoluteFileName(localFile) ) { TString tmp(localFile); tmp.ReplaceAll(GetMapValue("Snapshot"),""); tmp.ReplaceAll(GetMapValue("Local"),""); remote += tmp; } else { remote += localFile; } TString dirName = gSystem->DirName(remote.Data()); Bool_t ok(kTRUE); if (!RemoteDirectoryExists(dirName.Data())) { ok = gGrid->Mkdir(dirName.Data(),"-p"); } if ( ok ) { AliDebugClass(1,Form("cp %s alien://%s",local.Data(),remote.Data())); return TFile::Cp(local.Data(),Form("alien://%s",remote.Data())); } else { return kFALSE; } } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CheckRemoteDir() const { /// Check we have a grid connection and that the remote dir exists if (RemoteDir().IsNull()) { AliError("you must provide the grid location where to copy the files"); return kFALSE; } if (!RemoteDirectoryExists(RemoteDir())) { AliError(Form("directory %s does not exist", RemoteDir().Data())); return kFALSE; } return kTRUE; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CopyLocalFilesToRemote() { /// copy all files necessary to run the simulation into remote directory TIter next(LocalFileList()); TObjString* ftc; Bool_t allok(kTRUE); while ( ( ftc = static_cast(next())) ) { allok = allok && CopyFile(ftc->String()); } return allok; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::CopyTemplateFilesToLocal() { // copy (or generate) local files from the template ones if (!IsValid()) return kFALSE; AliDebug(1,""); TIter next(TemplateFileList()); TObjString* file; Int_t err(0); Bool_t potentialProblem(kFALSE); while ( ( file = static_cast(next())) ) { if ( file->String().Contains("OCDB") ) { /// OCDB snapshots are not in template continue; } if ( !ShouldOverwriteFiles() && !gSystem->AccessPathName(file->String().Data()) ) { AliError(Form("Local file %s already exists. Remove it first if you want to update overwrite it",file->String().Data())); potentialProblem = kTRUE; } else { TString stemplate(Form("%s/%s",TemplateDir().Data(),file->String().Data())); TString slocal(Form("%s/%s",LocalDir().Data(),file->String().Data())); Int_t c = gSystem->CopyFile(stemplate.Data(),slocal.Data(),ShouldOverwriteFiles()); if ( c ) { Bool_t ok(kFALSE); if ( stemplate.Contains(".jdl",TString::kIgnoreCase) ) { ok = Generate(file->String().Data()); } if (!ok) { AliError(Form("Error %d copying file %s",c,stemplate.Data())); } else { c=0; } } else { if ( HasVars(slocal.Data()) ) { if (!ReplaceVars(slocal.Data())) { AliError("pb in ReplaceVars"); c=1; } } } err += c; } } if ( potentialProblem ) { AliWarning("At least one local file could not be overwritten. Cross-check that the local files are OK before we try to upload them to the Grid !"); return kFALSE; } return (err==0); } //______________________________________________________________________________ std::ostream* AliMuonGridSubmitter::CreateJDLFile(const char* name) const { /// Create a (local and empty) JDL file AliDebugClass(1,""); TString jdl(Form("%s/%s",LocalDir().Data(),name)); if ( !ShouldOverwriteFiles() && !gSystem->AccessPathName(jdl.Data()) ) { AliErrorClass(Form("File %s already exists. Remove it if you want to overwrite it",jdl.Data())); return 0x0; } std::ofstream* os = new std::ofstream(gSystem->ExpandPathName(jdl.Data())); if (os->bad()) { AliErrorClass(Form("Cannot create file %s",jdl.Data())); delete os; os=0x0; } return os; } //______________________________________________________________________________ Int_t AliMuonGridSubmitter::GetLastStage(const char* remoteDir) { /// Get the last staging phase already performed TGridResult* r = gGrid->Ls(remoteDir); Int_t i(0); Int_t lastStage(0); Int_t offset = TString("Stage_").Length(); while ( r->GetFileName(i) ) { TString file(r->GetFileName(i)); if (file.BeginsWith("Stage_") && !file.Contains("xml") ) { Int_t n = TString(file(offset,file.Length()-offset)).Atoi(); lastStage = TMath::Max(lastStage,n); } ++i; } delete r; return lastStage; } //______________________________________________________________________________ TString AliMuonGridSubmitter::GetMapValue(const char* key) const { // convenience method to access internal map of TObjStrings if (!fInternalMap) return ""; TObject* o = fInternalMap->GetValue(key); if (o) { return static_cast(o)->String(); } return ""; } //______________________________________________________________________________ TObjArray* AliMuonGridSubmitter::GetVariables(const char* file) const { /// Find the variables in the file std::ifstream in(file); char line[1024]; TObjArray* variables(0x0); while ( in.getline(line,1023,'\n') ) { TString sline(line); while (sline.Contains("VAR_") && !sline.BeginsWith("//") ) { Int_t i1 = sline.Index("VAR_"); Int_t i2(i1); while ( ( i2 < sline.Length() ) && ( isalnum(sline[i2]) || sline[i2]=='_' ) ) ++i2; if (!variables) { variables = new TObjArray; variables->SetOwner(kTRUE); } TString var = sline(i1,i2-i1); if ( !variables->FindObject(var) ) { variables->Add(new TObjString(var)); } sline.ReplaceAll(var,""); } } in.close(); return variables; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::HasVars(const char* file) const { /// Whether or not the file contains variables that have to /// be substituted std::ifstream in(file); char line[1024]; while ( in.getline(line,1023,'\n') ) { TString sline(line); if (sline.Contains("VAR_") && !sline.BeginsWith("//") ) { return kTRUE; } } return kFALSE; } //______________________________________________________________________________ TMap* AliMuonGridSubmitter::InternalMap() const { if (!fInternalMap) { fInternalMap = new TMap; fInternalMap->SetOwnerKeyValue(kTRUE,kTRUE); } return fInternalMap; } //______________________________________________________________________________ TString AliMuonGridSubmitter::JobTypeName(AliMuonGridSubmitter::EJobType jobType) const { if ( jobType == kAccEff ) { return "AccEff"; } else if ( jobType == kQAMerge) { return "QAMerge"; } return "unknown"; } //______________________________________________________________________________ TObjArray* AliMuonGridSubmitter::LocalFileList() const { /// Return (after createing and filling it if needed) /// the internal file list with paths from the local directory if (!fLocalFileList) { fLocalFileList = static_cast(TemplateFileList()->Clone()); } return fLocalFileList; } //______________________________________________________________________________ UInt_t AliMuonGridSubmitter::NofRuns() const { // number of runs we're dealing with return fRunList.size(); } //______________________________________________________________________________ TObjArray* AliMuonGridSubmitter::OrderKeys(const TMap& map) const { /// return an array where the map's keys are sorted alphabetically /// the returned array should be deleted by the client TObjArray* keyArray = new TObjArray; keyArray->SetOwner(kTRUE); TObjString* key; TIter next(&map); while ( ( key = static_cast(next())) ) { keyArray->Add(new TObjString(key->String())); } keyArray->Sort(); return keyArray; } //______________________________________________________________________________ void AliMuonGridSubmitter::OutputToJDL(std::ostream& out, const char* key, const TObjArray& values) const { /// output to ostream of key,{values} pair out << key << " = "; Int_t n = values.GetEntries(); if ( n > 1 ) { out << "{" << std::endl; TIter next(&values); TObjString* v; while ( ( v = static_cast(next())) ) { --n; out << "\t\"" << v->String().Data() << "\""; if ( n ) out << ","; out << std::endl; } out << "}"; } else { TString& v1 = static_cast(values.At(0))->String(); if ( v1.IsDigit() && !(TString(key).Contains("SplitMax")) && !(TString(key).Contains("TTL")) ) { out << v1.Atoi(); } else { out << "\"" << v1.Data() << "\""; } } out << ";" << std::endl; } //______________________________________________________________________________ void AliMuonGridSubmitter::OutputToJDL(std::ostream& out, const char* key, const char* v1, const char* v2, const char* v3, const char* v4, const char* v5, const char* v6, const char* v7, const char* v8, const char* v9) const { /// output to ostream TObjArray values; values.SetOwner(kTRUE); values.Add(new TObjString(v1)); if ( strlen(v2) > 0 ) values.Add(new TObjString(v2)); if ( strlen(v3) > 0 ) values.Add(new TObjString(v3)); if ( strlen(v4) > 0 ) values.Add(new TObjString(v4)); if ( strlen(v5) > 0 ) values.Add(new TObjString(v5)); if ( strlen(v6) > 0 ) values.Add(new TObjString(v6)); if ( strlen(v7) > 0 ) values.Add(new TObjString(v7)); if ( strlen(v8) > 0 ) values.Add(new TObjString(v8)); if ( strlen(v9) > 0 ) values.Add(new TObjString(v9)); OutputToJDL(out,key,values); } //______________________________________________________________________________ void AliMuonGridSubmitter::Print(Option_t* /*opt*/) const { /// Printout if (!IsValid()) { std::cout << std::string(80,'*') << std::endl; std::cout << "INVALID OBJECT. CHECK BELOW THE CONFIGURATION." << std::endl; std::cout << std::string(80,'*') << std::endl; } std::cout << "-- Internals : " << std::endl; TObjArray* im = OrderKeys(*fInternalMap); TIter next(im); TObjString* key; while ( ( key = static_cast(next()) ) ) { TString value = static_cast(fInternalMap->GetValue(key->String()))->String(); std::cout << key->String() << " : " << value.Data() << std::endl; } delete im; if ( NofRuns() ) { std::cout << NofRuns() << " run"; if ( NofRuns() > 1 ) std::cout << "s"; std::cout << " = "; for ( std::vector::size_type i = 0; i < fRunList.size(); ++i ) { std::cout << fRunList[i] << " "; } std::cout << std::endl; } std::cout << std::endl << "-- Variables : " << std::endl; TObjArray* iv = OrderKeys(*fVars); TIter nextVar(iv); while ( ( key = static_cast(nextVar())) ) { TObjString* value = static_cast(fVars->GetValue(key->String())); std::cout << "Variable " << key->String() << " will be replaced by " << value->String() << std::endl; } delete iv; std::cout << std::endl << "-- Files to be uploaded:" << std::endl; TIter nextFile(LocalFileList()); TObjString* sfile; while ( ( sfile = static_cast(nextFile())) ) { std::cout << sfile->String().Data() << std::endl; } } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::RemoteDirectoryExists(const char *dirname) const { // Returns true if directory exists. Can be also a path. if (!gGrid) return kFALSE; // Check if dirname is a path TString dirstripped = dirname; dirstripped = dirstripped.Strip(); dirstripped = dirstripped.Strip(TString::kTrailing, '/'); TString dir = gSystem->BaseName(dirstripped); dir += "/"; TString path = gSystem->DirName(dirstripped); TGridResult *res = gGrid->Ls(path, "-F"); if (!res) return kFALSE; TIter next(res); TMap *map; TObject *obj; while ((map=dynamic_cast(next()))) { obj = map->GetValue("name"); if (!obj) break; if (dir == obj->GetName()) { delete res; return kTRUE; } } delete res; return kFALSE; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::RemoteFileExists(const char *lfn) { // Returns true if file exists. if (!gGrid) return kFALSE; TGridResult *res = gGrid->Ls(lfn); if (!res) return kFALSE; TMap *map = dynamic_cast(res->At(0)); if (!map) { delete res; return kFALSE; } TObjString *objs = dynamic_cast(map->GetValue("name")); if (!objs || !objs->GetString().Length()) { delete res; return kFALSE; } delete res; return kTRUE; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::ReplaceVars(const char* file) const { /// Replace the variables (i.e. things starting by VAR_) found in file std::ifstream in(file); char line[1024]; TObjArray lines; lines.SetOwner(kTRUE); Int_t nvars(0); Int_t nreplaced(0); TIter next(fVars); while ( in.getline(line,1023,'\n') ) { TString sline(line); while (sline.Contains("VAR_") && !sline.BeginsWith("//") ) { ++nvars; TObjString* key; next.Reset(); while ( ( key = static_cast(next())) ) { if ( sline.Contains(key->String()) ) { ++nreplaced; TObjString* value = static_cast(fVars->GetValue(key->String())); sline.ReplaceAll(key->String(),value->String()); break; } } } lines.Add(new TObjString(sline)); } in.close(); if ( nvars > 0 ) { if ( nreplaced != nvars ) { AliError(Form("nvars=%d nreplaced=%d",nvars,nreplaced)); return kFALSE; } std::ofstream out(file); TIter nextLine(&lines); TObjString* s; while ( ( s = static_cast(nextLine()) ) ) { out << s->String().Data() << std::endl; } out.close(); } return kTRUE; } //______________________________________________________________________________ const std::vector& AliMuonGridSubmitter::RunList() const { /// Return a reference to our runlist return fRunList; } //______________________________________________________________________________ void AliMuonGridSubmitter::SetPackages(const char* aliroot, const char* root, const char* geant3, const char* api) { /// Set the packages to be used by the jobs /// Must be a valid combination, see http://alimonitor.cern.ch/packages/ /// SetMapKeyValue("AliRoot",aliroot); SetMapKeyValue("Root",root); SetMapKeyValue("Geant3",geant3); SetMapKeyValue("API",api); } //______________________________________________________________________________ TString AliMuonGridSubmitter::GetRemoteDir(const char* dir, Bool_t create) { /// Set the target remote directory (on the grid) if (!RemoteDirectoryExists(dir)) { if (!create) { AliErrorClass(Form("Remote directory %s does not exist", dir)); return ""; } else { AliInfoClass(Form("Remote directory %s does not exist. Trying to create it...",dir)); if (!gGrid) { AliErrorClass("cannot connect to grid"); return ""; } if ( !gGrid->Mkdir(dir,"-p") ) { AliErrorClass(Form("Could not create remote dir. Sorry.")); return ""; } } } return dir; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::SetLocalDirectory(const char* type, const char* path) { if (gSystem->AccessPathName(path)==kFALSE) { SetMapKeyValue(type,path); return kTRUE; } return kFALSE; } //______________________________________________________________________________ void AliMuonGridSubmitter::SetMapKeyValue(const char* key, const char* value) { TObjString skey(key); InternalMap()->Remove(&skey); InternalMap()->Add(new TObjString(key),new TObjString(value)); } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::SetRemoteDirectory(const char* type, const char* path) { // Set the merged directory to be used TString v = GetRemoteDir(path,kTRUE); SetMapKeyValue(type,v); return (v.Length()>0); } //______________________________________________________________________________ void AliMuonGridSubmitter::SetRunList(const char* runlist) { // set the runlist from a text file AliAnalysisTriggerScalers ts(runlist); fRunList = ts.GetRunList(); } //______________________________________________________________________________ void AliMuonGridSubmitter::SetRunList(int runNumber) { // set the runlist from a text file fRunList.clear(); fRunList.push_back(runNumber); } //______________________________________________________________________________ TString AliMuonGridSubmitter::GetVar(const char* key) const { TObjString* o = static_cast(Vars()->GetValue(key)); if (o) { return o->String(); } return ""; } //______________________________________________________________________________ Bool_t AliMuonGridSubmitter::SetVar(const char* varname, const char* value) { /// Set a variable TString s(varname); s.ToUpper(); if (!s.BeginsWith("VAR_")) { AliError("Variable name should start with VAR_"); return kFALSE; } if (!fVars) { fVars = new TMap; fVars->SetOwnerKeyValue(kTRUE,kTRUE); } TObject* o = new TObjString(s); fVars->Remove(o); fVars->Add(o,new TObjString(value)); return kTRUE; } //______________________________________________________________________________ TObjArray* AliMuonGridSubmitter::TemplateFileList() const { /// Return (after createing if needed) if (!fTemplateFileList) { fTemplateFileList = new TObjArray; fTemplateFileList->SetOwner(kTRUE); } return fTemplateFileList; } //______________________________________________________________________________ void AliMuonGridSubmitter::UpdateLocalFileList() { // insure that local file list contains at least all of the template files TIter next(TemplateFileList()); TObjString* s; while ( ( s = static_cast(next())) ) { AddToLocalFileList(s->String().Data()); } } //______________________________________________________________________________ TMap* AliMuonGridSubmitter::Vars() const { if (!fVars) { fVars = new TMap; fVars->SetOwnerKeyValue(kTRUE,kTRUE); } return fVars; }