/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 #include "TouchableToDetectorElementFast.h" 00002 00003 #include "G4TouchableHistory.hh" 00004 00005 #include "DetDesc/ILVolume.h" 00006 #include "DetDesc/IPVolume.h" 00007 #include "DetDesc/IDetectorElement.h" 00008 #include "DetDesc/IGeometryInfo.h" 00009 00010 #include "GaudiKernel/DataObject.h" 00011 #include "GaudiKernel/IRegistry.h" 00012 #include "GaudiKernel/RegistryEntry.h" 00013 #include "GaudiKernel/DataObject.h" 00014 00015 #include <vector> 00016 00017 TouchableToDetectorElementFast::TouchableToDetectorElementFast( 00018 const std::string& type, 00019 const std::string& name, 00020 const IInterface* parent) 00021 : GaudiTool(type,name,parent) 00022 { 00023 declareInterface<ITouchableToDetectorElement>(this); 00024 ClearCache(); 00025 } 00026 00027 00028 StatusCode TouchableToDetectorElementFast::G4VolumeToDetDesc( 00029 const G4VPhysicalVolume* inVol, 00030 const IPVolume* &outVol ) 00031 { 00035 00036 Relation* relation; 00037 StatusCode sc = GetRelation(inVol,relation); 00038 if(sc.isFailure()) { 00039 // This error generates too much verbiage. 00040 //err() << "Couldn't find IPVolume for " << inVol->GetName() << endreq; 00041 outVol = 0; 00042 return sc; 00043 } 00044 outVol = relation->mPhysVol; 00045 if(outVol==0) return StatusCode::FAILURE; 00046 00047 return StatusCode::SUCCESS; 00048 } 00049 00050 00051 // --------------------------------------------------------------------------------- 00052 template <class T> 00053 StatusCode TouchableToDetectorElementFast::FindObjectsInDirectory( 00054 const std::string& dirname, 00055 std::list<const T*>& list 00056 ) 00057 { 00061 DataObject* d = 0; 00062 StatusCode sc = detSvc()->retrieveObject(dirname,d); 00063 00064 if(sc.isFailure()) return sc; 00065 00066 const T* t = dynamic_cast<const T*>(d); 00067 if(t) list.push_back(t); 00068 00069 IRegistry* dr = d->registry(); 00070 using namespace DataSvcHelpers; 00071 RegistryEntry* dre = dynamic_cast<RegistryEntry*>(dr); 00072 if (!dre) { 00073 err() << "Failed to get RegistryEntry on DataObject" << d << endreq; 00074 return StatusCode::FAILURE; 00075 } 00076 00077 RegistryEntry::Iterator it = dre->begin(), done = dre->end(); 00078 for (; it != done; ++it) { 00079 std::string id = (*it)->identifier(); 00080 StatusCode sc = FindObjectsInDirectory<T>(id,list); 00081 if(sc.isFailure()) return sc; 00082 } 00083 00084 return StatusCode::SUCCESS; 00085 } 00086 00087 00088 StatusCode TouchableToDetectorElementFast::GetBestDetectorElement( 00089 const G4TouchableHistory* inHistory, // The current particle location 00090 const std::vector<std::string>& inPaths,// Name(s) of specific detElements, or paths to be searched 00091 const IDetectorElement* &outElement, // output: The best element (may be zero!) 00092 int& outCompatibility ) // output: the goodness of the match (higher is better) 00093 { 00094 // First, look at the touchable volume and get the top-level directory, which should be our current DetectorElement. 00095 G4VPhysicalVolume* g4top = inHistory->GetVolume(inHistory->GetHistoryDepth()-1); 00096 if(!g4top) { 00097 err() << "Got null G4VPhysicalVolume pointer in the bottom of G4TouchableHistory. Huh???" << endreq; 00098 return StatusCode::FAILURE; 00099 } 00100 00101 00102 if( mWorldElementName != g4top->GetName() ) { 00103 // Uh oh! Our cache is bad. Clear it. 00104 ClearCache(); 00105 // Set the new one. 00106 if(!exist<IDetectorElement>(detSvc(),g4top->GetName()),false) { 00107 err() << "Can't find detector element at the bottom of the G4TouchableHistory, name = " << g4top->GetName() << endreq; 00108 return StatusCode::FAILURE; 00109 } 00110 00111 mWorldElement = getDet<IDetectorElement>(g4top->GetName()); 00112 mWorldElementName = mWorldElement->name(); 00113 if(!mWorldElement) { 00114 err() << "Unable to find world element. G4 top is " << g4top->GetName() << endreq; 00115 } 00116 } 00117 00118 // Ok, now build up the total relative path from the world element to the top of the TouchableHistory. 00119 ILVolume::ReplicaPath touchablePath; 00120 for(int ind=inHistory->GetHistoryDepth()-2; ind>=0; --ind){ 00121 G4VPhysicalVolume* g4pv = inHistory->GetVolume(ind); 00122 // Look it up. 00123 Relation* rel; 00124 StatusCode sc = GetRelation(g4pv,rel); 00125 if(sc.isFailure()){ 00126 err() << "Failure from GetRelation(" << g4pv->GetName() << ")" << endreq; 00127 return sc; 00128 } 00129 00130 // Tack this onto the end of the list. 00131 touchablePath.insert(touchablePath.end(),rel->mRpath.begin(),rel->mRpath.end()); 00132 00133 } // End loop over history 00134 00135 00136 // So, now we have our TouchablePath. Let's now look at each detelem. 00137 00138 00139 // Is this a new search, or does it match an old one? 00140 if(mLastSearchPaths == inPaths) { 00141 // Do nothing! Our cache is still good! 00142 } else { 00143 mElementList.clear(); 00144 // Search each path, looking for things. 00145 for(unsigned int i = 0; i< inPaths.size(); ++i) { 00146 info() << "Looking for structures in path " << inPaths[i] << endreq; 00147 StatusCode sc = FindObjectsInDirectory<IDetectorElement>(inPaths[i],mElementList); 00148 if(sc.isFailure()) { 00149 warning() << "Couldn't resolve DetectorElement search path " <<inPaths[i] << endreq; 00150 } 00151 } 00152 if (inPaths.size()) { 00153 // w/out this message a quiet, long running G4 looks like we are still taking up time 00154 info() << "Finished search structures in " << inPaths.size() << " paths" << endreq; 00155 } 00156 mLastSearchPaths = inPaths; 00157 } 00158 00159 // Default: none is best: 00160 // At the moment, the best possible match is to the top Element, which has only basic compatibility. 00161 outCompatibility = 0x7fffffff; // Maximum possible int. 00162 outElement = mWorldElement; 00163 00164 // Now compare each one to our current. 00165 ElementList_t::iterator it = mElementList.begin(); 00166 Relation* rel; 00167 while( it != mElementList.end() ) { 00168 if(*it==0) { 00169 err() << "Found a zero DetElem in our list. How did that happen?"<< endreq; 00170 ++it; continue; 00171 } 00172 StatusCode sc = GetRelation(*it,rel); 00173 if(sc.isFailure()) { ++it; continue; } 00174 00175 // Is it supported by our volume? 00176 if(rel->isNull()){ 00177 // delete this entry.. it's doing us no good. 00178 it = mElementList.erase(it); 00179 } else { 00180 ILVolume::ReplicaPath &elementPath = rel->mRpath; 00181 00182 int compat = Compatability(touchablePath,elementPath); 00183 if((compat>=0) && (compat<outCompatibility)) { 00184 outElement = *it; 00185 outCompatibility = compat; 00186 } 00187 ++it; 00188 } 00189 } 00190 00191 return StatusCode::SUCCESS; 00192 } 00193 00194 00196 int TouchableToDetectorElementFast::Compatability(const ILVolume::ReplicaPath& inPlace, 00197 const ILVolume::ReplicaPath& inContainer) 00198 { 00199 // Check to see that the container is at least as specific as the place. 00200 // If not, the container specifies a deeper detector element than the place 00201 // e.g. This condition catches container=PMT, place=rock 00202 unsigned int sizeContainer = inContainer.size(); 00203 unsigned int sizePlace = inPlace.size(); 00204 00205 if(sizeContainer > sizePlace) return -1; 00206 00207 // Check through to see if it matches at every level. 00208 ILVolume::ReplicaPath::const_iterator container_it = inContainer.begin(); 00209 ILVolume::ReplicaPath::const_iterator place_it = inPlace.begin(); 00210 ILVolume::ReplicaPath::const_iterator container_end = inContainer.end(); 00211 while(container_it != container_end) { 00212 if(*container_it != *place_it) return -1; 00213 container_it++; 00214 place_it++; 00215 } 00216 00217 // Ok, it checks at every level of the container. The goodness of the match is the specificity of the container. 00218 return sizePlace - sizeContainer; 00219 } 00220 00221 00222 00223 StatusCode TouchableToDetectorElementFast::GetRelation(const G4VPhysicalVolume* inVol, Relation* &outRelation ) 00224 { 00233 00234 if(!inVol) { 00235 return StatusCode::FAILURE; 00236 } 00237 00239 G4ToRelationMap_t::iterator it = mG4ToRelationMap.find(inVol); 00240 if(it != mG4ToRelationMap.end()) { 00241 outRelation = &(it->second); 00242 return StatusCode::SUCCESS; 00243 } 00244 00245 // Create the new lookup. 00246 Relation rel; 00247 00248 // Ok, we failed to find it. Time to do some actual work. 00249 std::string pvpath = inVol->GetName(); 00250 00251 const ILVolume* lv = 0; 00252 const IPVolume* pv = 0; 00253 // This is a top-level call 00254 // Look for an explicit logical volume name. 00255 std::string lname = pvpath; 00256 std::string::size_type p = pvpath.find_first_of('#'); 00257 if(p!= std::string::npos) { 00258 lname = pvpath.substr(0,p); 00259 pvpath.erase(0,p+1); // strip off this part. 00260 } 00261 00262 // Find the logical volume. 00263 if(!exist<ILVolume>(detSvc(),lname,false)) { 00264 // It's possible that we've hit the top (geant) volume, which is actually a DetectorElement. 00265 if(exist<IDetectorElement>(detSvc(),lname,false)) { 00266 // Ok, this is a special case. 00267 IDetectorElement* de = getDet<IDetectorElement>(lname); 00268 IGeometryInfo* geo = de->geometry(); 00269 assert(geo); 00270 if(geo->hasSupport()) { 00271 // This may be the top geant volume, but it's supported in DetDesc space. 00272 // So, find the support, and work down. 00273 ILVolume::ReplicaPath rpath; 00274 IGeometryInfo* nextgeo; 00275 geo->location(nextgeo, rpath); 00276 // take off one level. 00277 assert(rpath.size()>0); 00278 ILVolume::ReplicaType last = rpath.back(); 00279 rpath.pop_back(); 00280 lv = nextgeo->lvolume(nextgeo,rpath); 00281 pv = (*lv)[last]; 00282 // output. 00283 rel.mRpath = ILVolume::ReplicaPath(); // this case isn't valid in the overall tree 00284 rel.mLogVol = lv; 00285 rel.mPhysVol = pv; 00286 it = mG4ToRelationMap.insert(G4ToRelationMap_t::value_type(inVol,rel)).first; 00287 outRelation = &(it->second); 00288 return StatusCode::SUCCESS; 00289 } 00290 // Ok, this looks like something strange. 00291 if(geo->hasLVolume()) { 00292 lv = de->geometry()->lvolume(); 00293 // just try the first physvol. this is correct for the genuine top volume. 00294 pv = (*lv)[0]; 00295 rel.mRpath = ILVolume::ReplicaPath(); // this case isn't valid in the overall tree 00296 rel.mLogVol = lv; 00297 rel.mPhysVol = pv; 00298 it = mG4ToRelationMap.insert(G4ToRelationMap_t::value_type(inVol,rel)).first; 00299 outRelation = &(it->second); 00300 return StatusCode::SUCCESS; 00301 } 00302 00303 } 00304 // Wierd.. it's not an lvolume or a detelement, or the detelement couldn't be evaluated. 00305 err() << "Can't find lvolume at path " << lname << endreq; 00306 rel.mLogVol = 0; 00307 rel.mPhysVol = 0; 00308 rel.mRpath = ILVolume::ReplicaPath(); 00309 it = mG4ToRelationMap.insert(G4ToRelationMap_t::value_type(inVol,rel)).first; 00310 return StatusCode::FAILURE; 00311 } 00312 lv= getDet<ILVolume>(lname); 00313 // This is the correct supporting volume. 00314 rel.mLogVol = lv; 00315 00316 // Keep eating the remaining string until we have fully parsed the remaining logical/physical path sequence. 00317 while(pvpath.size() > 0) { 00318 // Make sure the current logical volume is good. 00319 if(!lv) { 00320 err() << "Can't find lvolume." << endreq; 00321 return StatusCode::FAILURE; 00322 } 00323 00324 // parse out the next bit before a hash mark: 00325 std::string pname = pvpath; 00326 std::string::size_type p = pvpath.find_first_of('#'); 00327 if(p != std::string::npos ) { 00328 pname.erase(p,std::string::npos); 00329 pvpath.erase(0,p+1); // Ok, take this stuff off the front. 00330 } else { 00331 pvpath.erase(); 00332 } 00333 00334 ILVolume::ReplicaType replica = 0; 00335 pv = 0; 00336 for ( ILVolume::ReplicaType i = 0; i< lv->noPVolumes(); ++i ){ 00337 const IPVolume* apv = lv->pvolume(i); 00338 if(!apv) { 00339 err() << "Bad link to IPVolume from " << lv->name() << endreq; 00340 return StatusCode::FAILURE; 00341 } 00342 // Look for a match. 00343 if(apv->name() == pname){ 00344 pv = apv; 00345 replica = i; 00346 break; 00347 } 00348 } // End of loop over physical volumes in lv 00349 00350 if(!pv) { 00351 err() << "Couldn't find a match for physical volume with name " << pname << " in lvolume name " << lv->name() << endreq; 00352 return StatusCode::FAILURE; 00353 } 00354 // Finally, this is what we were after: 00355 rel.mRpath.push_back(replica); 00356 00357 // Advance lvolume 00358 lv = pv->lvolume(); 00359 } 00360 00361 // The physical volume 00362 rel.mPhysVol = pv; 00363 00364 it = mG4ToRelationMap.insert(G4ToRelationMap_t::value_type(inVol,rel)).first; 00365 outRelation = &(it->second); 00366 00367 return StatusCode::SUCCESS; 00368 00369 00370 } 00371 00372 StatusCode TouchableToDetectorElementFast::GetRelation(const IDetectorElement* inElem, Relation* &outRelation ) 00373 { 00374 if(!inElem) return StatusCode::FAILURE; 00375 00376 // Check the cache... is it there? 00377 DetElemToRelationMap_t::iterator it = mDetElemToRelationMap.find(inElem); 00378 if(it != mDetElemToRelationMap.end()) { 00379 outRelation = &(it->second); 00380 return StatusCode::SUCCESS; 00381 } 00382 00383 // It's not in the cache, so we actually have to do some work. 00384 Relation rel; 00385 00389 const IGeometryInfo* topGeo = mWorldElement->geometry(); 00390 const IGeometryInfo* trialGeo = inElem->geometry(); 00391 00392 // Try to build up a full replica path. 00393 rel.mRpath.clear(); 00394 00395 const IGeometryInfo* curGeo = trialGeo; 00396 while(curGeo!=topGeo) { 00397 //std::string sstart; 00398 //curGeo->location(sstart, rpath); 00399 00400 ILVolume::ReplicaPath rpath; 00401 IGeometryInfo* nextGeo; 00402 curGeo->location(nextGeo, rpath); 00403 curGeo = nextGeo; 00404 rel.mRpath.insert(rel.mRpath.begin(),rpath.begin(),rpath.end()); 00405 if(0==curGeo) break; 00406 } 00407 if(curGeo==topGeo) { 00408 // We reached the top and it's a match to our world volume. Success! 00409 rel.mLogVol = curGeo->lvolume(); 00410 // Navigate back to our physical volume. 00411 const ILVolume* lv = rel.mLogVol; 00412 const IPVolume* pv = 0; 00413 for(unsigned int i=0;i<rel.mRpath.size();i++) { 00414 if(lv) 00415 pv = (*lv)[rel.mRpath[i]]; 00416 if(pv) 00417 lv = pv->lvolume(); 00418 } 00419 rel.mPhysVol = pv; 00420 } 00421 else { 00422 // 00423 // This is an error, but I don't know how to fix it.. how do you go from GeometryInfo to a detector element, 00424 // especially if it's an 'orphan' or a 'ghost'? Maybe it doesn't matter, since it isnt' used. 00425 } 00426 00427 it = mDetElemToRelationMap.insert(DetElemToRelationMap_t::value_type(inElem,rel)).first; 00428 outRelation = &(it->second); 00429 00430 return StatusCode::SUCCESS; 00431 00432 } 00433 00434 00435 StatusCode TouchableToDetectorElementFast::ClearCache() 00436 { 00437 mWorldElement =0; 00438 mWorldElementName = ""; 00439 mG4ToRelationMap.clear(); 00440 mDetElemToRelationMap.clear(); 00441 mLastSearchPaths.clear(); 00442 mElementList.clear(); 00443 return StatusCode::SUCCESS; 00444 }