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
00040
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,
00090 const std::vector<std::string>& inPaths,
00091 const IDetectorElement* &outElement,
00092 int& outCompatibility )
00093 {
00094
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
00104 ClearCache();
00105
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
00119 ILVolume::ReplicaPath touchablePath;
00120 for(int ind=inHistory->GetHistoryDepth()-2; ind>=0; --ind){
00121 G4VPhysicalVolume* g4pv = inHistory->GetVolume(ind);
00122
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
00131 touchablePath.insert(touchablePath.end(),rel->mRpath.begin(),rel->mRpath.end());
00132
00133 }
00134
00135
00136
00137
00138
00139
00140 if(mLastSearchPaths == inPaths) {
00141
00142 } else {
00143 mElementList.clear();
00144
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
00154 info() << "Finished search structures in " << inPaths.size() << " paths" << endreq;
00155 }
00156 mLastSearchPaths = inPaths;
00157 }
00158
00159
00160
00161 outCompatibility = 0x7fffffff;
00162 outElement = mWorldElement;
00163
00164
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
00176 if(rel->isNull()){
00177
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
00200
00201
00202 unsigned int sizeContainer = inContainer.size();
00203 unsigned int sizePlace = inPlace.size();
00204
00205 if(sizeContainer > sizePlace) return -1;
00206
00207
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
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
00246 Relation rel;
00247
00248
00249 std::string pvpath = inVol->GetName();
00250
00251 const ILVolume* lv = 0;
00252 const IPVolume* pv = 0;
00253
00254
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);
00260 }
00261
00262
00263 if(!exist<ILVolume>(detSvc(),lname,false)) {
00264
00265 if(exist<IDetectorElement>(detSvc(),lname,false)) {
00266
00267 IDetectorElement* de = getDet<IDetectorElement>(lname);
00268 IGeometryInfo* geo = de->geometry();
00269 assert(geo);
00270 if(geo->hasSupport()) {
00271
00272
00273 ILVolume::ReplicaPath rpath;
00274 IGeometryInfo* nextgeo;
00275 geo->location(nextgeo, rpath);
00276
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
00283 rel.mRpath = ILVolume::ReplicaPath();
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
00291 if(geo->hasLVolume()) {
00292 lv = de->geometry()->lvolume();
00293
00294 pv = (*lv)[0];
00295 rel.mRpath = ILVolume::ReplicaPath();
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
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
00314 rel.mLogVol = lv;
00315
00316
00317 while(pvpath.size() > 0) {
00318
00319 if(!lv) {
00320 err() << "Can't find lvolume." << endreq;
00321 return StatusCode::FAILURE;
00322 }
00323
00324
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);
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
00343 if(apv->name() == pname){
00344 pv = apv;
00345 replica = i;
00346 break;
00347 }
00348 }
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
00355 rel.mRpath.push_back(replica);
00356
00357
00358 lv = pv->lvolume();
00359 }
00360
00361
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
00377 DetElemToRelationMap_t::iterator it = mDetElemToRelationMap.find(inElem);
00378 if(it != mDetElemToRelationMap.end()) {
00379 outRelation = &(it->second);
00380 return StatusCode::SUCCESS;
00381 }
00382
00383
00384 Relation rel;
00385
00389 const IGeometryInfo* topGeo = mWorldElement->geometry();
00390 const IGeometryInfo* trialGeo = inElem->geometry();
00391
00392
00393 rel.mRpath.clear();
00394
00395 const IGeometryInfo* curGeo = trialGeo;
00396 while(curGeo!=topGeo) {
00397
00398
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
00409 rel.mLogVol = curGeo->lvolume();
00410
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
00424
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 }