/search.css" rel="stylesheet" type="text/css"/> /search.js">
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

TouchableToDetectorElementFast.cc
Go to the documentation of this file.
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 }
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Fri May 16 2014 10:05:42 for G4DataHelpers by doxygen 1.7.4