#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "HEPConstants.hxx" #include "ICOMETLog.hxx" #include "IGeometryId.hxx" #include "COMETGeomId.hxx" #include "COMETGeomIdDef.hxx" #include "IGeomIdManager.hxx" #include "IOADatabase.hxx" #include "ICOMETEvent.hxx" #include "IGeomIdFinder.hxx" #include "ICDCIdFinder.hxx" #include "ICTHIdFinder.hxx" #include "IStrawTrkIdFinder.hxx" #include "IECALIdFinder.hxx" #include "ITOFIdFinder.hxx" #include "ICosmicVetoIdFinder.hxx" COMET::IGeomIdManager::IGeomIdManager() :fRootUnitLength(unit::cm) ,fGeometryPointerOverride(0) ,fGeometryFileOverride("") ,fGeometryHashOverride(ISHAHashValue()) ,fGeoManager(0) { fRootUnitLength2 = fRootUnitLength*fRootUnitLength; ResetGeometry(); } COMET::IGeomIdManager::~IGeomIdManager() {} bool COMET::IGeomIdManager::CdId(const IGeometryId& id) const { GeomIdKey gid = MakeGeomIdKey(id); GeomIdMap::const_iterator pair = fGeomIdMap.find(gid); if (pair != fGeomIdMap.end()) return CdKey(pair->second); // The geometry id was not found. Check to see if this is one of the // special cases. return false; } bool COMET::IGeomIdManager::FindGeometryId(IGeometryId& id) const { // Save the current node. gGeoManager->PushPath(); bool success = true; do { // Get the key into the map for the current node. RootGeoKey rik = MakeRootGeoKey(); if (gGeoManager->GetTopNode() == gGeoManager->GetCurrentNode()) { success = false; break; } // Find the key in the map. RootIdMap::const_iterator rim = fRootIdMap.find(rik); // Don't have a geometry id for this node. if (rim == fRootIdMap.end()) { gGeoManager->CdUp(); continue; } id = MakeGeometryId(rim->second); break; } while (true); // Return the the original state. gGeoManager->PopPath(); return success; } bool COMET::IGeomIdManager::GetPosition(const IGeometryId& id,TVector3& position) const { return LocalToMaster(id,0,0,0,position); } bool COMET::IGeomIdManager::GetPosition(const int id,TVector3& position) const { return LocalToMaster(id,0,0,0,position); } bool COMET::IGeomIdManager::MasterToLocal(const IGeometryId& geomId, double x, double y, double z, TVector3 & newpos) const { gGeoManager->PushPath(); if (!CdId(geomId)){ COMETError("Invalid geom Id: \""<PopPath(); return false; } const double master[3] = {x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength}; double local[3]; gGeoManager->MasterToLocal(master,local); gGeoManager->PopPath(); newpos = TVector3(local)*(fRootUnitLength); return true; } bool COMET::IGeomIdManager::MasterToLocal(int nodeId, double x, double y, double z, TVector3 & newpos) const { if (nodeId<0){ COMETError("Invalid node Id: "<PushPath(); gGeoManager->CdNode(nodeId); const double master[3] = {x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength}; double local[3]; gGeoManager->MasterToLocal(master,local); gGeoManager->PopPath(); newpos = TVector3(local)*(fRootUnitLength); return true; } bool COMET::IGeomIdManager::MasterToLocalVect(const IGeometryId& geomId, double x, double y, double z, TVector3 & newvec) const { gGeoManager->PushPath(); if (!CdId(geomId)){ COMETError("Invalid geom Id: \""<PopPath(); return false; } const double master[3] = {x,y,z}; double local[3]; gGeoManager->MasterToLocalVect(master,local); gGeoManager->PopPath(); newvec = TVector3(local); return true; } bool COMET::IGeomIdManager::MasterToLocalVect(int nodeId, double x, double y, double z, TVector3 & newvec) const { if (nodeId<0){ COMETError("Invalid node Id: "<PushPath(); gGeoManager->CdNode(nodeId); const double master[3] = {x,y,z}; double local[3]; gGeoManager->MasterToLocalVect(master,local); gGeoManager->PopPath(); newvec = TVector3(local); return true; } bool COMET::IGeomIdManager::LocalToMaster(const IGeometryId& geomId, double x, double y, double z, TVector3 & newpos) const { gGeoManager->PushPath(); if (!CdId(geomId)){ COMETError("Invalid geom Id: \""<PopPath(); return false; } const double local[3] = {x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength}; double master[3]; gGeoManager->LocalToMaster(local,master); gGeoManager->PopPath(); newpos = TVector3(master)*(fRootUnitLength); return true; } bool COMET::IGeomIdManager::LocalToMaster(int nodeId, double x, double y, double z, TVector3 & newpos) const { if (nodeId<0){ COMETError("Invalid node Id: "<PushPath(); gGeoManager->CdNode(nodeId); const double local[3] = {x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength}; double master[3]; gGeoManager->LocalToMaster(local,master); gGeoManager->PopPath(); newpos = TVector3(master)*(fRootUnitLength); return true; } bool COMET::IGeomIdManager::LocalToMasterVect(const IGeometryId& geomId, double x, double y, double z, TVector3 & newvec) const { gGeoManager->PushPath(); if (!CdId(geomId)){ COMETError("Invalid geom Id: \""<PopPath(); return false; } const double local[3] = {x,y,z}; double master[3]; gGeoManager->LocalToMasterVect(local,master); gGeoManager->PopPath(); newvec = TVector3(master); return true; } bool COMET::IGeomIdManager::LocalToMasterVect(int nodeId, double x, double y, double z, TVector3 & newvec) const { if (nodeId<0){ COMETError("Invalid node Id: "<PushPath(); gGeoManager->CdNode(nodeId); const double local[3] = {x,y,z}; double master[3]; gGeoManager->LocalToMasterVect(local,master); gGeoManager->PopPath(); newvec = TVector3(master); return true; } TGeoNode * COMET::IGeomIdManager::GetNode(int nodeId) const{ if (nodeId<0){ COMETError("Invalid node Id: "<PushPath(); gGeoManager->CdNode(nodeId); TGeoNode* node = gGeoManager->GetCurrentNode(); gGeoManager->PopPath(); return node; } TGeoNode * COMET::IGeomIdManager::GetNode(const IGeometryId& geomId) const{ gGeoManager->PushPath(); if (!CdId(geomId)){ gGeoManager->PopPath(); COMETError("Invalid geom Id: \""<GetCurrentNode(); gGeoManager->PopPath(); return node; } TGeoNode * COMET::IGeomIdManager::FindNode(double x, double y, double z) const{ gGeoManager->PushPath(); gGeoManager->GetTopNode()->cd(); TGeoNode* node = gGeoManager->FindNode(x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength); gGeoManager->PopPath(); return node; } TGeoNode * COMET::IGeomIdManager::FindNodeAndEnter(double x, double y, double z) const{ gGeoManager->GetTopNode()->cd(); TGeoNode* node = gGeoManager->FindNode(x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength); return node; } TGeoNode * COMET::IGeomIdManager::FindNode(const TVector3 & position) const{ return FindNode(position.X(),position.Y(),position.Z()); } TGeoNode * COMET::IGeomIdManager::FindNodeAndEnter(const TVector3 & position) const{ return FindNodeAndEnter(position.X(),position.Y(),position.Z()); } int COMET::IGeomIdManager::FindNodeId(double x, double y, double z) const{ gGeoManager->PushPath(); gGeoManager->GetTopNode()->cd(); gGeoManager->FindNode(x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength); int node = gGeoManager->GetCurrentNodeId(); gGeoManager->PopPath(); return node; } int COMET::IGeomIdManager::FindNodeId(const TVector3 & position) const{ return FindNodeId(position.X(),position.Y(),position.Z()); } std::string COMET::IGeomIdManager::FullNodePath(double x, double y, double z) const{ gGeoManager->PushPath(); gGeoManager->GetTopNode()->cd(); gGeoManager->FindNode(x/fRootUnitLength,y/fRootUnitLength,z/fRootUnitLength); std::string path = gGeoManager->GetPath(); gGeoManager->PopPath(); return path; } std::string COMET::IGeomIdManager::FullNodePath(const TVector3 & position) const{ return FullNodePath(position.X(),position.Y(),position.Z()); } std::string COMET::IGeomIdManager::FullNodePath(int nodeId) const{ if (nodeId<0){ COMETError("Invalid node Id: "<PushPath(); gGeoManager->CdNode(nodeId); std::string path = gGeoManager->GetPath(); gGeoManager->PopPath(); return path; } std::string COMET::IGeomIdManager::NodeName(IGeometryId id) const { if (!gGeoManager) return "not-available"; if (fGeomIdMap.empty()) return "not-available"; if (id == IGeometryId()) return "empty"; gGeoManager->PushPath(); if (!CdId(id)) { COMETError("Invalid geom Id: \""<PopPath(); return "invalid"; } std::string result = gGeoManager->GetCurrentNode()->GetName(); gGeoManager->PopPath(); return result; } TVector3 COMET::IGeomIdManager::NodePosition(const IGeometryId& id) const { TVector3 position(0,0,0); GetPosition(id,position); return position; } TVector3 COMET::IGeomIdManager::NodePosition(const int id) const { TVector3 position(0,0,0); GetPosition(id,position); return position; } const TGeoHMatrix* COMET::IGeomIdManager::NodeMatrix(const int id) const { gGeoManager->PushPath(); gGeoManager->CdNode(id); TGeoHMatrix* matrix = gGeoManager->GetCurrentMatrix(); gGeoManager->PopPath(); return matrix; } const TGeoVolume* COMET::IGeomIdManager::NodeVolume(const int id) const { gGeoManager->PushPath(); gGeoManager->CdNode(id); TGeoVolume* volume = gGeoManager->GetCurrentVolume(); gGeoManager->PopPath(); return volume; } TVector3 COMET::IGeomIdManager::NodeExtent(const COMET::IHit& hit, ShapeType shapeType) const { return NodeExtent(hit.GetGeomID(),shapeType); } TVector3 COMET::IGeomIdManager::NodeExtent(const IGeometryId& geomId, ShapeType shapeType) const { TVector3 master(0,0,0); TVector3 spread(0,0,0); TVector3 local = NodeSize(geomId,shapeType); LocalToMasterVect(geomId,local.X(),0,0,master); for (int i=0; i<3; ++i) spread[i] = std::max(spread[i],std::abs(master[i])); LocalToMasterVect(geomId,0,local.Y(),0,master); for (int i=0; i<3; ++i) spread[i] = std::max(spread[i],std::abs(master[i])); LocalToMasterVect(geomId,0,0,local.Z(),master); for (int i=0; i<3; ++i) spread[i] = std::max(spread[i],std::abs(master[i])); return spread; } TVector3 COMET::IGeomIdManager::NodeSize(const IGeometryId& geomId, ShapeType shapeType) const{ gGeoManager->PushPath(); if (!CdId(geomId)){ gGeoManager->PopPath(); COMETError("Invalid geom Id: \""<GetCurrentNode(); TVector3 vec = NodeSize(node,shapeType); gGeoManager->PopPath(); return vec; } TVector3 COMET::IGeomIdManager::NodeSize(const TGeoNode* node, ShapeType shapeType) const{ TVector3 vec(0,0,0); switch (shapeType){ case kBox:{ TGeoBBox *shape = dynamic_cast(node->GetVolume()->GetShape()); if (!shape){ COMETError("Cannot convert shape into TGeoBBox!"); } else{ vec.SetX(shape->GetDX()*(fRootUnitLength)); vec.SetY(shape->GetDY()*(fRootUnitLength)); vec.SetZ(shape->GetDZ()*(fRootUnitLength)); } break; } case kTube:{ TGeoTube *shape = dynamic_cast(node->GetVolume()->GetShape()); if (!shape){ COMETError("Cannot convert shape into TGeoTube!"); } else{ vec.SetX(shape->GetRmax()*(fRootUnitLength)); vec.SetY(shape->GetRmax()*(fRootUnitLength)); vec.SetZ(shape->GetDZ()*(fRootUnitLength)); } break; } default: { COMETError("IGeometryId doesn't support this type yet!"); } } return vec; } double COMET::IGeomIdManager::X0(TGeoMaterial * mat, int method) const { // In SimG4 we explicitly defined material with following units: // density: g/cm3 // A: g/mole // RadLen: cm // These definition are hard coded and not related with the defautl unit chose by HEPUnits double x0 = 0; switch ( method ) { case 2: // simplified PDG method (PDG 2006 sec 27.4) { double Z = mat->GetZ(); if ( Z > 0. ) { x0 = 716.4*mat->GetA()/ (Z*(Z+1)*log(287./sqrt(Z))); // g/cm2 } x0 /= mat->GetDensity(); // g/cm3 x0 *= unit::cm; // cm } break; case 1: // full PDG method (PDG 2006 sec 27.4) { double Lrad = 0.; double Lrad_prime = 0.; double Z = mat->GetZ(); if ( (int)Z == 1 ) { Lrad = 5.31; Lrad_prime = 6.144; } else if ( (int)Z == 2 ) { Lrad = 4.79; Lrad_prime = 5.621; } else if ( (int)Z == 3 ) { Lrad = 4.74; Lrad_prime = 5.805; } else if ( (int)Z == 4 ) { Lrad = 4.71; Lrad_prime = 5.924; } else { Lrad = log(184.15*pow(Z,-1./3.)); Lrad_prime = log(1194. *pow(Z,-2./3.)); } double a2 = pow(unit::fine_structure_const*Z,2.); double f_Z = a2*(1./(1.+a2)+0.20206-0.0369*a2+0.0083*a2*a2+0.0082*a2*a2*a2); double x0inv = (1./716.408)/ (mat->GetA())* (Z*Z*(Lrad-f_Z)+Z*Lrad_prime); if ( x0inv != 0. ) x0 = 1./x0inv; // g/cm2 x0 /= mat->GetDensity(); // g/cm3 x0 *= unit::cm; // cm } break; default: case 0: { x0 = mat->GetRadLen()*unit::cm; // cm } break; } return x0; } bool COMET::IGeomIdManager::GetGeometryId(double x, double y, double z, IGeometryId& id) const { gGeoManager->PushPath(); FindNodeAndEnter(x,y,z); bool success = FindGeometryId(id); gGeoManager->PopPath(); return success; } void COMET::IGeomIdManager::ResetGeometry() { fGeomIdMap.clear(); fRootIdMap.clear(); fGeomIdHashCode = ISHAHashValue(); fGeomIdChangedHash = ISHAHashValue(); fGeomIdAlignmentId = IAlignmentId(); fGeomEventContext = ICOMETContext(); SetGeoManager(gGeoManager); if (!gGeoManager) { COMETNamedDebug("Geometry","ResetGeometry with invalid gGeoManager"); return; } BuildHashCode(); if (!GetHash().Valid()) { COMETError("Geometry reset, but no valid hash is available"); return; } // See if the geometry already has an alignment applied. GetAlignmentCode(fGeomIdAlignmentId); BuildGeomIdMap(); // Lock the geometry into memory. gGeoManager->LockGeometry(); } bool COMET::IGeomIdManager::LoadGeometry(TFile& file, const COMET::ISHAHashValue& hc, const COMET::IAlignmentId& align) { if (!file.IsOpen()) { COMETError("Geometry file not available"); return false; } file.cd(); std::ostringstream rexp; rexp << std::hex << std::nouppercase << std::setfill('0'); rexp << "^COMETGeometry-"; if (hc(0) != 0) rexp << std::setw(8) << hc(0); else rexp << "[[:xdigit:]]{8}"; if (hc(1) != 0) rexp << "-" << std::setw(8) << hc(1); else rexp << "-[[:xdigit:]]{8}"; if (hc(2) != 0) rexp << "-" << std::setw(8) << hc(2); else rexp << "-[[:xdigit:]]{8}"; if (hc(3) != 0) rexp << "-" << std::setw(8) << hc(3); else rexp << "-[[:xdigit:]]{8}"; if (hc(4) != 0) rexp << "-" << std::setw(8) << hc(4); else rexp << "-[[:xdigit:]]{8}"; TPRegexp geometryRegExp(rexp.str().c_str()); rexp << ":"; if (align(0) != 0) rexp << std::setw(8) << align(0); else rexp << "[[:xdigit:]]{8}"; if (align(1) != 0) rexp << "-" << std::setw(8) << align(1); else rexp << "-[[:xdigit:]]{8}"; if (align(2) != 0) rexp << "-" << std::setw(8) << align(2); else rexp << "-[[:xdigit:]]{8}"; if (align(3) != 0) rexp << "-" << std::setw(8) << align(3); else rexp << "-[[:xdigit:]]{8}"; if (align(4) != 0) rexp << "-" << std::setw(8) << align(4); else rexp << "-[[:xdigit:]]{8}"; TPRegexp alignedRegExp(rexp.str().c_str()); // Find the right key. TKey* defaultKey = NULL; TKey* geometryKey = NULL; TKey* alignedKey = NULL; TIter next(file.GetListOfKeys()); TKey* key; while ((key = dynamic_cast(next()))) { if (!defaultKey && std::string(key->GetName()) == "COMETGeometry") { defaultKey = key; } if (!geometryKey && TString(key->GetName()).Contains(geometryRegExp)) { geometryKey = key; } if (!alignedKey && TString(key->GetName()).Contains(alignedRegExp)) { alignedKey = key; } } key = defaultKey; if (geometryKey) key = geometryKey; if (alignedKey) key = alignedKey; if (!key) { return false; } // Unprotect the geometry so we can load a new one. if (gGeoManager) gGeoManager->UnlockGeometry(); TGeoManager *saveGeom = gGeoManager; TGeoManager *geom= dynamic_cast(file.Get(key->GetName())); if (!geom) { gGeoManager = saveGeom; return false; } std::string fileName(gSystem->BaseName(file.GetName())); COMETLog("Geometry read from " << fileName); // Check to see if the hash code should be taken from the file name. ISHAHashValue newCode; if (!GetHashCode(newCode) && fileName.find("geom-") != std::string::npos && fileName.find(".root") != std::string::npos && ParseHashCode(fileName.substr( fileName.find("geom-")+5,100),newCode)) { // The hash code is saved in the file name so save it SaveHashCode(newCode); } ResetGeometry(); return true; } std::string COMET::IGeomIdManager::FindGeometryFile(const ISHAHashValue& hc) const { std::string result = ""; std::string oaEventRoot(gSystem->Getenv("OAEVENTROOT")); std::string oaEventConfig(gSystem->Getenv("OAEVENTCONFIG")); std::string geometryName = oaEventRoot + "/" + oaEventConfig; void* dirp = gSystem->OpenDirectory(geometryName.c_str()); if (!dirp) { COMETSevere("Geometry directory not available:" " Run comet-get-geometry."); return result; } // Build a regular expression to look for the file name. std::ostringstream rexp; rexp << std::hex << std::nouppercase << std::setfill('0'); rexp << "geom-"; if (hc(0) != 0) rexp << std::setw(8) << hc(0); else rexp << "[[:xdigit:]]{8}"; if (hc(1) != 0) rexp << "-" << std::setw(8) << hc(1); else rexp << "-[[:xdigit:]]{8}"; if (hc(2) != 0) rexp << "-" << std::setw(8) << hc(2); else rexp << "-[[:xdigit:]]{8}"; if (hc(3) != 0) rexp << "-" << std::setw(8) << hc(3); else rexp << "-[[:xdigit:]]{8}"; if (hc(4) != 0) rexp << "-" << std::setw(8) << hc(4); else rexp << "-[[:xdigit:]]{8}"; rexp << ".root$"; TPRegexp regExp(rexp.str().c_str()); while (const char *fileName = gSystem->GetDirEntry(dirp)) { if (!TString(fileName).Contains(regExp)) continue; // This is the geometry we are looking for. result = geometryName + "/" + fileName; break; } gSystem->FreeDirectory(dirp); return result; } bool COMET::IGeomIdManager::ReadGeometry(const COMET::ISHAHashValue& hc) { std::string inputName = FindGeometryFile(hc); if (inputName.empty()) { COMETSevere("No geometry matchs hash: " << hc); return false; } TFile* inputPtr(TFile::Open(inputName.c_str(),"OLD")); if (!inputPtr) { COMETError("Cannot open geometry file: " << inputName); return false; } std::auto_ptr inFile(inputPtr); return LoadGeometry(*inFile,hc); } void COMET::IGeomIdManager::SaveHashCode(const ISHAHashValue& hc) { std::ostringstream hash; if (!hc.Valid()) { COMETSevere("Trying to save invalid hash code"); return; } std::string name(gGeoManager->GetName()); // Make sure we are starting from a standarized name. if (name.find("COMETGeometry-")!=0) name = "COMETGeometry-"; hash << std::hex << std::nouppercase << std::setfill('0'); hash << "-" << std::setw(8) << hc(0); hash << "-" << std::setw(8) << hc(1); hash << "-" << std::setw(8) << hc(2); hash << "-" << std::setw(8) << hc(3); hash << "-" << std::setw(8) << hc(4); std::string::size_type start = name.find("-"); std::string::size_type length = std::min(name.length()-start, name.find(":")-start); name.replace(start, length, hash.str()); gGeoManager->SetName(name.c_str()); } bool COMET::IGeomIdManager::GetHashCode(COMET::ISHAHashValue& hc) const { hc = COMET::ISHAHashValue(); std::string name(gGeoManager->GetName()); // Check that the name is "reasonable". if (name.find("COMETGeometry-") != 0) { return false; } if (name.size() < 58) { COMETNamedDebug("Geometry","Name length wrong: " << name.size()); return false; } if (!ParseHashCode(name.substr(14,256),hc)) { COMETNamedDebug("Geometry","Name not parsed: " << name.substr(14,256)); return false; } return true; } void COMET::IGeomIdManager::SaveAlignmentCode(const COMET::IAlignmentId& aid) { std::ostringstream hash; std::string name(gGeoManager->GetName()); // Make sure we are starting from a standarized name. if (name.find("COMETGeometry-")!=0) { COMETSevere("Cannot save alignment id. Invalid geometry name"); return; } if (name.length()<58) { COMETSevere("Cannot save alignment id. No hash code saved"); return; } if (!aid.Valid()) { std::string::size_type start = name.find(":"); if (start != std::string::npos) { name.erase(start); gGeoManager->SetName(name.c_str()); } return; } hash << std::hex << std::nouppercase << std::setfill('0'); hash << ":" << std::setw(8) << aid(0); hash << "-" << std::setw(8) << aid(1); hash << "-" << std::setw(8) << aid(2); hash << "-" << std::setw(8) << aid(3); hash << "-" << std::setw(8) << aid(4); std::string::size_type start = name.find(":"); if (start == 58) { std::string::size_type length = name.length()-start; name.replace(start, length, hash.str()); } else if (start == std::string::npos) { name = name + hash.str(); } gGeoManager->SetName(name.c_str()); } bool COMET::IGeomIdManager::GetAlignmentCode(COMET::IAlignmentId& aid) const { aid = COMET::IAlignmentId(); std::string name(gGeoManager->GetName()); // Check that the name is "reasonable". if (name.find("COMETGeometry-") != 0) { return false; } if (name.find(":") != 58) { return false; } if (name.size() < 102) { COMETNamedDebug("Geometry","Name length wrong: " << name.size()); return false; } if (!ParseHashCode(name.substr(59,256),aid)) { COMETNamedDebug("Geometry","Name not parsed: " << name.substr(59,256)); return false; } return true; } bool COMET::IGeomIdManager::ParseHashCode(std::string name, COMET::ISHAHashValue& hc) const { unsigned int htemp[5]; std::string parseName = name; int dash = parseName.find('-'); if (dash != 8) { COMETNamedDebug("Geometry",name); COMETNamedDebug("Geometry","Bad code -- '-' in wrong place: " << dash); return false; } std::istringstream hash0(parseName.substr(0,8)); hash0 >> std::hex >> htemp[0]; parseName = parseName.substr(dash+1,100); dash = parseName.find('-'); if (dash != 8) { COMETNamedDebug("Geometry",name); COMETNamedDebug("Geometry","Bad code -- '-' in wrong place: " << dash); return false; } std::istringstream hash1(parseName.substr(0,8)); hash1 >> std::hex >> htemp[1]; parseName = parseName.substr(dash+1,100); dash = parseName.find('-'); if (dash != 8) { COMETNamedDebug("Geometry",name); COMETNamedDebug("Geometry","Bad code -- '-' in wrong place: " << dash); return false; } std::istringstream hash2(parseName.substr(0,8)); hash2 >> std::hex >> htemp[2]; parseName = parseName.substr(dash+1,100); dash = parseName.find('-'); if (dash != 8) { COMETNamedDebug("Geometry",name); COMETNamedDebug("Geometry","Bad code -- '-' in wrong place: " << dash); return false; } std::istringstream hash3(parseName.substr(0,8)); hash3 >> std::hex >> htemp[3]; parseName = parseName.substr(dash+1,100); if (parseName.size() < 8) { COMETNamedDebug("Geometry",name); COMETNamedDebug("Geometry","Bad code -- last value short: " << parseName.size()); return false; } std::istringstream hash4(parseName); hash4 >> std::hex >> htemp[4]; hc = COMET::ISHAHashValue(htemp); return true; } bool COMET::IGeomIdManager::CdKey(const RootGeoKey& key) const { // This is the only place that should need to be changed if the RootGeoKey // type is redefined. int nodeid = key; if (nodeid<0){ COMETError("Invalid node Id: "<CdNode(nodeid); return true; } COMET::IGeomIdManager::RootGeoKey COMET::IGeomIdManager::MakeRootGeoKey() const { // This knows how to translate the current TGeoManager node into a // RootGeoKey object. The initial implementation is trivially simple. return gGeoManager->GetCurrentNodeId(); } COMET::IGeomIdManager::GeomIdKey COMET::IGeomIdManager::MakeGeomIdKey(IGeometryId id) const { // This knows how to take IGeometryId object and translate it into a // GeomIdKey that can be used with the fGeomIdMap. For some values of the // IGeometryId objects, this will have to apply a mask to the integer // value (since a root volume may be associated with more than one // IGeometryId values). GeomIdKey gik = id.AsInt(); return gik; } COMET::IGeometryId COMET::IGeomIdManager::MakeGeometryId(GeomIdKey key) const { // This knows how to take a GeomIdKey and translate it into a // IGeometryId object. return IGeometryId(key); } void COMET::IGeomIdManager::BuildGeomIdMap() { // DO NOT CALL IOADatabase::Get().UpdateGeometry() HERE // Make sure that the node id array has been initialized in the // TGeoNodeCache. if (!gGeoManager->GetCache()->HasIdArray()) { gGeoManager->GetCache()->BuildIdArray(); } // Set the top volume. TGeoVolume* top = gGeoManager->GetTopVolume(); std::string topName(top->GetName()); if (topName != "comet") { COMETWarn("Geometry top volume has changed to " << topName); top = gGeoManager->GetVolume("comet"); if (!top) { COMETError("No comet volume in geometry"); return; } COMETWarn("Resetting top volume to " << top->GetName()); gGeoManager->SetTopVolume(top); } // Clear the current geom id map. fGeomIdMap.clear(); fRootIdMap.clear(); // Save the current geometry state. gGeoManager->PushPath(); gGeoManager->CdTop(); // Create the geometry identifier finders. if (!fFinders.empty()) { COMETSevere("fFinders vector should be empty"); fFinders.clear(); } fFinders.push_back(new ICDCIdFinder()); fFinders.push_back(new ICTHIdFinder()); fFinders.push_back(new IStrawTrkIdFinder()); fFinders.push_back(new IECALIdFinder()); fFinders.push_back(new ITOFIdFinder()); fFinders.push_back(new ICosmicVetoIdFinder()); // Initialize to begin recursion. std::vector names; names.reserve(20); int keepGoing = 0; for (std::vector::iterator f = fFinders.begin(); f != fFinders.end(); ++f) keepGoing = 2*keepGoing + 1; RecurseGeomId(names,keepGoing); // Delete all of the geometry identifier finders. for (std::vector::iterator f = fFinders.begin(); f != fFinders.end(); ++f) { delete (*f); } fFinders.clear(); // Restore the state. gGeoManager->PopPath(); COMETLog("Geometry identifier map with " << fGeomIdMap.size() << " entries."); } int COMET::IGeomIdManager::RecurseGeomId(std::vector& names, int keepGoing) { // DO NOT CALL IOADatabase::Get().UpdateGeometry() HERE TGeoNode* node = gGeoManager->GetCurrentNode(); names.push_back(node->GetName()); // Call each of the finders that still want to see the geometry. int mask = 0; for (std::vector::iterator f = fFinders.begin(); f != fFinders.end(); ++f) { mask = (mask) ? mask << 1: 1; if (0 == (keepGoing&mask)) continue; // Search with a particular finder. The finder will throw an // EGeomIdStop exception when it doesn't want to search any further. try { IGeometryId id; if ((*f)->Search(names, id)) { if (!id.IsValid()) { COMETError("Invalid IGeometryId from " << typeid((*f)).name()); continue; } if (id.GetSubsystemName() == "node") { COMETError("Plain node IGeometryId from " << typeid((*f)).name()); continue; } if (id.GetSubsystemName() == "unknown") { COMETError("Unknown IGeometryId from " << typeid((*f)).name()); continue; } GeomIdKey gik = MakeGeomIdKey(id); RootGeoKey rgk = MakeRootGeoKey(); GeomIdMap::iterator g = fGeomIdMap.find(gik); if (g != fGeomIdMap.end()) { COMETError("Duplicate id: " << gik); for(std::vector::const_iterator it=names.begin(); it != names.end(); it++){ std::cout << "/" << (*it).c_str(); } std::cout << std::endl; continue; } fGeomIdMap[gik] = rgk; fRootIdMap[rgk] = gik; } } catch (EGeomIdStop& e) { keepGoing &= ~mask; } catch (...) { COMETError("Unknown exception from finder"); } } // If some of them want to go deeper in the tree, keep recursing. if (keepGoing) { // Recurse through all of the daughters. for (int i=0; iGetNdaughters(); ++i) { gGeoManager->CdDown(i); RecurseGeomId(names, keepGoing); } } // Pop this node off the "stack" gGeoManager->CdUp(); names.pop_back(); return keepGoing; } void COMET::IGeomIdManager::BuildHashCode() { // DO NOT CALL IOADatabase::Get().UpdateGeometry() HERE // Make sure that the node id array has been initialized in the // TGeoNodeCache. if (!gGeoManager->GetCache()->HasIdArray()) { gGeoManager->GetCache()->BuildIdArray(); } // Check to see if there is already a hash code. If we have a hash code, // then don't recalculate. if (GetHashCode(fGeomIdHashCode)) return; COMETNamedDebug("Geometry", "Rebuild hash code"); // Set the top volume. TGeoVolume* top = gGeoManager->GetTopVolume(); std::string topName(top->GetName()); if (topName != "comet") { COMETWarn("Geometry top volume has changed to " << topName); top = gGeoManager->GetVolume("comet"); if (!top) { COMETError("No comet volume in geometry"); return; } COMETWarn("Resetting top volume to " << top->GetName()); gGeoManager->SetTopVolume(top); } // Save the current geometry state. gGeoManager->PushPath(); gGeoManager->CdTop(); // Clear the message digest. fSHA1.Reset(); // Initialize to begin recursion. std::vector names; names.reserve(20); RecurseHashCode(names); // Get the message digest and save it in the geometry. unsigned int messageDigest[5]; if (fSHA1.Result(messageDigest)) { fGeomIdHashCode = ISHAHashValue(messageDigest); COMETNamedDebug("Geometry","Built hash code: " << fGeomIdHashCode); SaveHashCode(fGeomIdHashCode); } else { COMETSevere("IGeomIdManager:: Could not build hash code"); fGeomIdHashCode = ISHAHashValue(); SaveHashCode(fGeomIdHashCode); } // Restore the state. gGeoManager->PopPath(); } void COMET::IGeomIdManager::RecurseHashCode(std::vector& names) { // DO NOT CALL IOADatabase::Get().UpdateGeometry() HERE TGeoNode* node = gGeoManager->GetCurrentNode(); names.push_back(node->GetName()); // Add this node to the ISHA1 message digest. The hash key is built out of // the name of the path, and the local position of the node in the parent // coordinate system. fSHA1 << gGeoManager->GetPath(); const double*const translation = node->GetMatrix()->GetTranslation(); fSHA1.Input(translation[0]); fSHA1.Input(translation[1]); fSHA1.Input(translation[2]); for (int i=0; iGetNdaughters(); ++i) { gGeoManager->CdDown(i); RecurseHashCode(names); } // Pop this node off the "stack" gGeoManager->CdUp(); names.pop_back(); } std::string COMET::IGeomIdManager::GetPath(IGeometryId id) const { if (!gGeoManager) return "not-available"; if (fGeomIdMap.empty()) return "not-available"; if (id == IGeometryId()) return "empty"; gGeoManager->PushPath(); if (!CdId(id)) { gGeoManager->PopPath(); return "invalid"; } std::string result = gGeoManager->GetPath(); gGeoManager->PopPath(); return result; } void COMET::IGeomIdManager::SetGeoManager(TGeoManager* g) { gGeoManager = fGeoManager = g; } TGeoManager* COMET::IGeomIdManager::GetGeoManager() { gGeoManager = fGeoManager; return gGeoManager; } TGeoManager* COMET::IGeomIdManager::GetGeometry() { if (!fGeoManager){ COMETError("You are calling IGeomIdManager::GetGeometry with no geometry set yet."); throw std::runtime_error("You are calling IGeomIdManager::GetGeometry with no geometry set yet."); } if (fGeoManager!=gGeoManager){ COMETWarn("gGeoManager got modified elsewhere. Will set gGeoManager to fGeoManager."); gGeoManager = fGeoManager; } return fGeoManager; } bool COMET::IGeomIdManager::FindAndLoadGeometry(COMET::ICOMETEvent* event) { // Check to see if the geometry has already been overloaded if (GetGeometryHashOverride().Equivalent(GetHash())) { COMETNamedDebug("Geometry","Correct geometry override already loaded"); return false; } // Check to see if we have a file to override the default geometry. if (!GetGeometryFileOverride().empty() || GetGeometryHashOverride().Valid()) { COMETNamedDebug("Geometry","Override standard geometry"); if (!GetGeometryFileOverride().empty()) { TFile *filePtr = TFile::Open(GetGeometryFileOverride().c_str(),"OLD"); if (!filePtr) { COMETNamedWarn("Geometry", " Geometry override file does not exist."); } else { std::auto_ptr file(filePtr); if (LoadGeometry(*file,COMET::ISHAHashValue())) { COMETNamedInfo("Geometry","Override geometry from " << file->GetName()); SetGeometryHashOverride(GetHash()); return true; } } } if (GetGeometryHashOverride().Valid()) { if (ReadGeometry(GetGeometryHashOverride())) { COMETNamedInfo("Geometry","Override geometry hash " << GetGeometryHashOverride()); SetGeometryHashOverride(GetHash()); return true; } } } // Check to see if there is a geometry in the current file. This // overrides the default geometry. ISHAHashValue hc; IAlignmentId aid; if (event) { hc = event->GetGeometryHash(); aid = event->GetAlignmentId(); } TFile* currentInputFile = IOADatabase::Get().CurrentInputFile(); if (!currentInputFile) { COMETNamedWarn("Geometry", " Input file not available to provide geometry"); } else if (LoadGeometry(*currentInputFile,hc,aid)) { COMETNamedInfo("Geometry", "Geometry loaded from " << currentInputFile->GetName()); return true; } else if (hc.Valid()) { COMETNamedWarn("Geometry", "Event needs geom w/ " << hc << ", but not in file"); } // As a last resort, try to use the geometry that was specified as the // default. While this is the last resort, this is the "normal" code // path. hc = COMET::IOADatabase::Get().FindEventGeometry(event); if (hc.Valid() && !GetHash().Equivalent(hc)) { COMETNamedInfo("Geometry","Look for geometry with " << hc); if (ReadGeometry(hc)) { COMETNamedInfo("Geometry","Geometry loaded with from database"); return true; } } COMETNamedDebug("Geometry","Geometry not loaded (no valid method found)"); return false; } namespace { // A local (and very simple) lock class to prevent UpdateGeometry from being // called recursively. class ILocalGeometryLock { public: ILocalGeometryLock() {++fLockCount;} ~ILocalGeometryLock() __attribute__((optimize("-O0"))){ --fLockCount; if (fLockCount<0) fLockCount = 0; } bool IsLocked() {return fLockCount>1;} int LockCount() {return fLockCount;} private: static int fLockCount; }; int ILocalGeometryLock::fLockCount=0; }; TGeoManager* COMET::IGeomIdManager::UpdateGeometry(COMET::ICOMETEvent* event) { ILocalGeometryLock geomLock; if (geomLock.IsLocked()) { // The geometry is currently being accessed, so don't do any geometry // checks. COMETNamedWarn("Geometry","Recursive Geometry Access: Lock count is " << geomLock.LockCount()); return gGeoManager; } // Make sure that gGeoManager points to the current value of fGeoManager. // This is a bit redundant since it will be done (again) by // CheckGeometry(), but it doesn't hurt to be careful. GetGeoManager(); // Save the current gFile so we can return to the current state. TFile* oldFile = gFile; std::string oldDirectory; if (oldFile) oldDirectory = oldFile->GetPath(); // Check to see if the geometry might have changed. If it might have // changed, then reload the geometry. bool geometryChanging = false; if (CheckGeometry(event)) { COMETNamedDebug("Geometry","Check for the correct geometry"); if (FindAndLoadGeometry(event)) { geometryChanging = true; COMETNamedDebug("Geometry", "Loaded geometry w/ hash: " << GetHash()); } } if (event) { if (event->GetGeometryHash().Valid() && !event->GetGeometryHash().Equivalent(GetHash())) { COMETNamedWarn("Geometry","Event geometry has been changed"); COMETNamedDebug("Geometry"," Old hash: " << event->GetGeometryHash()); COMETNamedDebug("Geometry"," New hash: " << GetHash()); } event->SetGeometryHash(GetHash()); } // Check to see if the alignment might have changed. if (CheckAlignment(event)) { geometryChanging = true; ApplyAlignment(event); } if (event) { if (event->GetAlignmentId().Valid() && !event->GetAlignmentId().Equivalent(GetAlignmentId())) { COMETNamedWarn("Geometry","Event alignment has changed"); COMETNamedDebug("Geometry"," Old hash: " << event->GetAlignmentId()); COMETNamedDebug("Geometry"," New hash: " << GetAlignmentId()); } event->SetAlignmentId(GetAlignmentId()); } // Make sure that gFile hasn't changed during this call. if (oldFile && oldFile != gFile) oldFile->cd(oldDirectory.c_str()); // Make sure we have a valid geometry and return an exception if we do // not. if (!GetGeoManager()) { COMETError("No Geometry is available."); throw ENoGeometry(); } // Notify the users that the geometry changed or doesn't match the last // "changed hash". if (geometryChanging || !fGeomIdChangedHash.Equivalent(GetHash())) { fGeomIdChangedHash = GetHash(); COMET::IOADatabase::Get().ApplyGeometryCallbacks(event); COMETLog("Loaded " << GetGeoManager()->GetName()); } // Stash the current time stamp. if (event) SetGeomEventContext(event->GetContext()); return GetGeoManager(); } bool COMET::IGeomIdManager::CheckGeometry(const COMET::ICOMETEvent* const event) { // Check to see if the geometry has been overriden if (GetGeometryHashOverride().Equivalent(GetHash())) { return false; } else if (GetGeometryHashOverride().Valid()) return true; else if (!GetGeometryFileOverride().empty()) return true; else if (GetGeometryPointerOverride()){ if (GetGeometryPointerOverride()!=fGeoManager){ COMETWarn("fGeoManager was set without using SetGeometryPointerOverride. Now fGeoManager will be set back to fGeometryPointerOverride."); SetGeoManager(GetGeometryPointerOverride()); } return false; } // We don't have an event so we can't determine the correct geometry. For // now, just print an error message, but this is actually a pretty serious // problem. In the future, this will return false. if (!event) { COMETError("Invalid event: Using suspicious geometry."); #define LOAD_DEFAULT_GEOMETRY #ifndef LOAD_DEFAULT_GEOMETRY return false; #else COMETNamedError("Geometry","Using suspicious geometry: This probably means that the geometry has been accessed in BeginFile() and is probably wrong. This worked in previous code, but depends on an oaEvent bug will be fixed in a future release. Code should be modified to use the COMET::IOADatabase::IGeometryLookup class so that it is notified when the geometry changed."); #endif } // If we don't have any geometry manager, then we have to look for one. if (!GetGeoManager()) { COMETNamedInfo("Geometry","Reload Geometry -- Not currently loaded"); return true; } // The current geometry hash code isn't valid. if (!GetHash().Valid()) { COMETNamedInfo("Geometry","Reload Geometry -- Current Hash Invalid"); return true; } // We don't have an event so don't change the geometry. if (!event) return false; // See if the current event geometry hash has changed. if (event->GetGeometryHash().Equivalent(GetHash())) { return false; } // If the event doesn't have a valid geometry hash, then only check the // geometry if the run number as changed. First make sure that the // geometry manager has seen a valid event, and then don't check the // geometry if the run numbers match. if (!event->GetGeometryHash().Valid() && GetGeomEventContext().GetRun() != COMET::ICOMETContext::Invalid && GetGeomEventContext().GetRun() == event->GetContext().GetRun()) { return false; } return true; } bool COMET::IGeomIdManager::CheckAlignment(const COMET::ICOMETEvent* const event) { // We don't have an alignment yet so we need to load one. if (!GetAlignmentId().Valid()) return true; // Don't change the alignment if there isn't an event and we already have // a valid alignment. if (!event) return false; // Don't change the alignment if the event already uses the current // alignment. This can be overridden by reseting the event alignment id. if (event->GetAlignmentId().Equivalent(GetAlignmentId())) return false; // The event doesn't use the current alignment. This means it either // doesn't have an alignment, or was calibrated using a different // alignment. Use the database code to see if the alignment needs to be // checked. If this returns false we will keep the current alignment. If // it returns true the geometry will be realigned. return COMET::IOADatabase::Get().CheckAlignment(event); } void COMET::IGeomIdManager::ApplyAlignment(const COMET::ICOMETEvent* const event) { if (!gGeoManager) { COMETSevere("ApplyAlignment called with invalid geometry"); return; } if (!GetHash().Valid()) { COMETError("ApplyAlignment called with invalid geometry tables"); return; } COMETNamedDebug("Geometry","Apply alignment to event"); fGeomIdAlignmentId = COMET::IOADatabase::Get().ApplyAlignmentLookup(event); SaveAlignmentCode(fGeomIdAlignmentId); }