00001
00006 #include "DsPmtSensDet.h"
00007 #include "DsPmtModel.h"
00008
00009 #include "Event/SimPmtHit.h"
00010
00011 #include "Conventions/Detectors.h"
00012
00013 #include "GiGaCnv/IGiGaGeomCnvSvc.h"
00014
00015 #include "GaudiKernel/ToolHandle.h"
00016
00017 #include "DetDesc/DetectorElement.h"
00018
00019 #include "GaudiKernel/IRndmGenSvc.h"
00020
00021 #include "G4DataHelpers/ITouchableToDetectorElement.h"
00022
00023 #include "G4Step.hh"
00024 #include "G4HCofThisEvent.hh"
00025 #include "G4SDManager.hh"
00026 #include "G4StepPoint.hh"
00027 #include "G4Region.hh"
00028 #include "G4LogicalVolume.hh"
00029 #include "G4VFastSimulationModel.hh"
00030 #include "G4ProductionCuts.hh"
00031 #include "G4ThreeVector.hh"
00032 #include "G4TouchableHistory.hh"
00033
00034 #include "G4OpticalPhoton.hh"
00035
00036 #include "CLHEP/Units/PhysicalConstants.h"
00037
00038 #include <string>
00039 #include <vector>
00040 #include <cstdio>
00041 using namespace std;
00042
00043 DetectorId::DetectorId_t detector_ids[] =
00044 { DetectorId::kAD1, DetectorId::kAD2, DetectorId::kAD3,
00045 DetectorId::kAD4, DetectorId::kIWS, DetectorId::kOWS,
00046 (DetectorId::DetectorId_t)-1 };
00047
00048 Site::Site_t site_ids[] =
00049 { Site::kDayaBay, Site::kLingAo, Site::kFar, (Site::Site_t)-1 };
00050
00051
00052 DsPmtSensDet::DsPmtSensDet(const std::string& type,
00053 const std::string& name,
00054 const IInterface* parent)
00055 : G4VSensitiveDetector(name)
00056 , GiGaSensDetBase(type,name,parent)
00057 , m_t2de(0)
00058 {
00059 info() << "DsPmtSensDet (" << type << "/" << name << ") created" << endreq;
00060
00061 declareProperty("CathodeLogicalVolume",
00062 m_cathodeLogVols,
00063 "Photo-Cathode logical volume to which this SD is attached.");
00064
00065 declareProperty("TouchableToDetelem", m_t2deName = "TH2DE",
00066 "The ITouchableToDetectorElement to use to resolve sensor.");
00067
00068 declareProperty("SensorStructures",m_sensorStructures,
00069 "TDS Paths in which to look for sensor detector elements"
00070 " using this sensitive detector");
00071
00072 declareProperty("PackedIdPropertyName",m_idParameter="PmtID",
00073 "The name of the user property holding the PMT ID.");
00074
00075 declareProperty("QEffParameterName",m_qeffParamName="EFFICIENCY",
00076 "name of user parameter in the photo cathode volume that"
00077 " holds the quantum efficiency tabproperty");
00078
00079 declareProperty("QEScale",m_qeScale=1.0 / 0.9,
00080 "Upward scaling of the quantum efficiency by inverse of mean PMT-to-PMT efficiency in electronics simulation.");
00081
00082 declareProperty("PreQE", m_preQE=0.32,
00083 "Miximal possible PMT QE value to be applied on the stage of "
00084 "generating photons in scintillation/Cerenkov processes");
00085
00086 declareProperty("ApplyPreQE",m_applyPreQE=true,
00087 "Apply preQE on stage of generating photons of not.");
00088
00089 m_cathodeLogVols.push_back("/dd/Geometry/PMT/lvPmtHemiCathode");
00090 m_cathodeLogVols.push_back("/dd/Geometry/PMT/lvHeadonPmtCathode");
00091 }
00092
00093 DsPmtSensDet::~DsPmtSensDet()
00094 {
00095 }
00096
00097 StatusCode DsPmtSensDet::initialize()
00098 {
00099 this->GiGaSensDetBase::initialize();
00100 info() << "DsPmtSensDet initialize" << endreq;
00101
00102 m_t2de = tool<ITouchableToDetectorElement>(m_t2deName);
00103
00104
00105
00106
00107 collectionName.insert("unknown");
00108 for (int isite=0; site_ids[isite] >= 0; ++isite) {
00109 Site::Site_t site = site_ids[isite];
00110
00111 for (int idet=0; detector_ids[idet] >= 0; ++idet) {
00112 DetectorId::DetectorId_t detid = detector_ids[idet];
00113
00114 DayaBay::Detector det(site,detid);
00115
00116 if (det.bogus()) continue;
00117
00118 string name=det.detName();
00119 collectionName.insert(name.c_str());
00120 debug() << "Inserted collectionName " << collectionName.size()-1
00121 << " = \"" << name << "\""
00122 << "(" << isite << "," << idet << "): "
00123 << "(" << site << "," << detid << ")"
00124 << endreq;
00125 }
00126 }
00127
00128
00129
00130
00131
00132
00133 IGiGaGeomCnvSvc *geoSvc = 0;
00134 if (service("GiGaGeo",geoSvc,true).isFailure()) {
00135 fatal() << "Failed to get GiGa Geometry service" << endreq;
00136 return StatusCode::FAILURE;
00137 }
00138 std::vector<std::string>::iterator volumeIter,
00139 volumeEnd = m_cathodeLogVols.end();
00140 int PMTii = 1;
00141 char str[10] = "";
00142
00143 for(volumeIter = m_cathodeLogVols.begin(); volumeIter != volumeEnd;
00144 volumeIter++){
00145 std::string cathodeLogVol = *volumeIter;
00146 G4LogicalVolume* lv = geoSvc->g4LVolume( cathodeLogVol );
00147 if (!lv) {
00148 error() << "Failed to get " << cathodeLogVol << endreq;
00149 return StatusCode::FAILURE;
00150 }
00151 std::string PMT_region_name = "PMT_region";
00152 std::string PmtModel_name = "PmtModel";
00153 sprintf(str,"%d",PMTii);
00154 PMT_region_name += str;
00155 PmtModel_name += str;
00156 PMTii++;
00157
00158 G4Region* pmt_reg = new G4Region(PMT_region_name.c_str());
00159 pmt_reg->AddRootLogicalVolume(const_cast<G4LogicalVolume*>(lv));
00160
00161 vector<double> cuts;
00162 cuts.push_back(1.0*mm);
00163 cuts.push_back(1.0*mm);
00164 cuts.push_back(1.0*mm);
00165 pmt_reg->SetProductionCuts(new G4ProductionCuts());
00166 pmt_reg->GetProductionCuts()->SetProductionCuts(cuts);
00167
00168 DsPmtModel* pmtModel = new DsPmtModel(PmtModel_name.c_str(),pmt_reg);
00169 pmtModel = 0;
00170 }
00171
00172
00173 IRndmGenSvc *rgs = 0;
00174 if (service("RndmGenSvc",rgs,true).isFailure()) {
00175 fatal() << "Failed to get random service" << endreq;
00176 return StatusCode::FAILURE;
00177 }
00178 StatusCode sc = m_uni.initialize(rgs, Rndm::Flat(0,1));
00179 if (sc.isFailure()) {
00180 fatal() << "Failed to initialize uniform random numbers" << endreq;
00181 return StatusCode::FAILURE;
00182 }
00183
00184 info()<<"Photons prescaling is "<<( m_applyPreQE?"on":"off" )
00185 <<". Preliminary applied efficiency is "<<m_preQE<<endreq;
00186 info()<<"Make sure the same values are set for the DsPhysConsOptical"<<endreq;
00187
00188 return StatusCode::SUCCESS;
00189 }
00190
00191 StatusCode DsPmtSensDet::finalize()
00192 {
00193 info() << "DsPmtSensDet finalize" << endreq;
00194 return this->GiGaSensDetBase::finalize();
00195 }
00196
00197
00198 void DsPmtSensDet::Initialize(G4HCofThisEvent* hce)
00199 {
00200 m_hc.clear();
00201
00202 G4DhHitCollection* hc = new G4DhHitCollection(SensitiveDetectorName,collectionName[0]);
00203 m_hc[0] = hc;
00204 int hcid = G4SDManager::GetSDMpointer()->GetCollectionID(hc);
00205 hce->AddHitsCollection(hcid,hc);
00206
00207 for (int isite=0; site_ids[isite] >= 0; ++isite) {
00208 for (int idet=0; detector_ids[idet] >= 0; ++idet) {
00209 DayaBay::Detector det(site_ids[isite],detector_ids[idet]);
00210
00211 if (det.bogus()) continue;
00212
00213 string name=det.detName();
00214 G4DhHitCollection* hc = new G4DhHitCollection(SensitiveDetectorName,name.c_str());
00215 short int id = det.siteDetPackedData();
00216 m_hc[id] = hc;
00217
00218 int hcid = G4SDManager::GetSDMpointer()->GetCollectionID(hc);
00219 hce->AddHitsCollection(hcid,hc);
00220 debug() << "Add hit collection with hcid=" << hcid << ", cached ID="
00221 << (void*)id
00222 << " name= \"" << SensitiveDetectorName << "/" << name << "\""
00223 << endreq;
00224 }
00225 }
00226
00227 debug() << "DsPmtSensDet Initialize, made "
00228 << hce->GetNumberOfCollections() << " collections"
00229 << endreq;
00230
00231 }
00232
00233
00234 const DetectorElement* DsPmtSensDet::SensDetElem(const G4TouchableHistory& hist)
00235 {
00236 const IDetectorElement* idetelem = 0;
00237 int steps=0;
00238
00239 if (!hist.GetHistoryDepth()) {
00240 error() << "DsPmtSensDet::SensDetElem given empty touchable history" << endreq;
00241 return 0;
00242 }
00243
00244 StatusCode sc =
00245 m_t2de->GetBestDetectorElement(&hist,m_sensorStructures,idetelem,steps);
00246 if (sc.isFailure()) {
00247 warning() << "Failed to find detector element in:\n";
00248 for (size_t ind=0; ind<m_sensorStructures.size(); ++ind) {
00249 warning() << "\t\t" << m_sensorStructures[ind] << "\n";
00250 }
00251 warning() << "\tfor touchable history:\n";
00252 for (int ind=0; ind < hist.GetHistoryDepth(); ++ind) {
00253 warning() << "\t (" << ind << ") "
00254 << hist.GetVolume(ind)->GetName() << "\n";
00255 }
00256 warning() << endreq;
00257 return 0;
00258 }
00259
00260 return dynamic_cast<const DetectorElement*>(idetelem);
00261 }
00262
00263 int DsPmtSensDet::SensDetId(const DetectorElement& de)
00264 {
00265 const DetectorElement* detelem = &de;
00266
00267 while (detelem) {
00268 if (detelem->params()->exists(m_idParameter)) {
00269 break;
00270 }
00271 detelem = dynamic_cast<const DetectorElement*>(detelem->parentIDetectorElement());
00272 }
00273 if (!detelem) {
00274 warning() << "Could not get PMT detector element starting from " << de << endreq;
00275 return 0;
00276 }
00277
00278 return detelem->params()->param<int>(m_idParameter);
00279 }
00280 double DsPmtSensDet::SensDetQE(G4LogicalVolume* logvol, double energy)
00281 {
00282 G4Material* mat = logvol->GetMaterial();
00283 if (!mat) {
00284 warning () << "No material for " << logvol->GetName() << endreq;
00285 return -1;
00286 }
00287
00288
00289 G4MaterialPropertiesTable* mattab = mat->GetMaterialPropertiesTable();
00290 if (mattab) {
00291 G4MaterialPropertyVector* qevec = mattab->GetProperty(m_qeffParamName.c_str());
00292 if (qevec) {
00293
00294 debug() << m_qeffParamName << ":("
00295 << qevec->GetMinPhotonEnergy()/CLHEP::eV << " eV,"
00296 << qevec->GetMinProperty() << ")-->("
00297 << qevec->GetMaxPhotonEnergy()/CLHEP::eV << " eV,"
00298 << qevec->GetMaxProperty() << ")"
00299 << " particle energy is " << energy/CLHEP::eV
00300 << endreq;
00301
00302 return qevec->GetProperty(energy);
00303
00304 }
00305 }
00306 else {
00307 debug () << "No material properties in " << logvol->GetName() << endreq;
00308 }
00309
00310 int ndaught = logvol->GetNoDaughters();
00311 for (int ind=0; ind < ndaught; ++ind) {
00312 G4VPhysicalVolume* physvol = logvol->GetDaughter(ind);
00313 double qe = this->SensDetQE(physvol->GetLogicalVolume(),energy);
00314 if (qe < 0) return qe;
00315 }
00316 warning() << "All attempts failed to find " << m_qeffParamName
00317 << " in " << logvol->GetName() << endreq;
00318 return -1;
00319 }
00320
00321 bool DsPmtSensDet::ProcessHits(G4Step* step,
00322 G4TouchableHistory* )
00323 {
00324
00325
00326
00327 G4StepPoint* preStepPoint = step->GetPreStepPoint();
00328
00329 double energyDep = step->GetTotalEnergyDeposit();
00330
00331 if (energyDep <= 0.0) {
00332
00333 return false;
00334 }
00335
00336 const G4TouchableHistory* hist =
00337 dynamic_cast<const G4TouchableHistory*>(preStepPoint->GetTouchable());
00338 if (!hist or !hist->GetHistoryDepth()) {
00339 error() << "ProcessHits: step has no or empty touchable history" << endreq;
00340 return false;
00341 }
00342
00343 const DetectorElement* de = this->SensDetElem(*hist);
00344 if (!de) return false;
00345
00346
00347 int pmtid = this->SensDetId(*de);
00348 DayaBay::Detector detector(pmtid);
00349 G4Track* track = step->GetTrack();
00350 double weight = track->GetWeight();
00351
00352
00353
00354
00355
00356
00357 if ( track->GetDefinition() != G4OpticalPhoton::Definition() )
00358 {
00359 debug() << "Track definition " << track->GetDefinition()->GetParticleName()
00360 << "This track is not an optical photon. abort further processing " << endreq;
00361 return false;
00362 }
00363
00364 double qe = this->SensDetQE(preStepPoint->GetPhysicalVolume()->GetLogicalVolume(),energyDep);
00365
00366
00367
00368
00369
00370 qe *= m_qeScale;
00371
00372
00373 if (detector.detectorId() == DetectorId::kIWS || detector.detectorId() == DetectorId::kOWS) {
00374 qe *= 0.6;
00375 }
00376 if (qe < 0.) return false;
00377 if ( m_applyPreQE ) qe/=m_preQE;
00378 if (qe > 1.) {
00379 warning() << "Non physical QE > 1." << endreq;
00380 }
00381
00382
00383 double looser = m_uni();
00384
00385 if (looser > qe) {
00386
00387 return true;
00388 }
00389
00390
00391 double wavelength = CLHEP::twopi*CLHEP::hbarc/energyDep;
00392
00393 #if 1
00394 if (!pmtid) {
00395 warning () << "Dumping TouchableHistory:\n";
00396 for (int ind=0; ind<hist->GetHistoryDepth(); ++ind) {
00397 warning () << "\t (" << ind << ") " << hist->GetVolume(ind)->GetName()
00398 << " #" << hist->GetReplicaNumber(ind)
00399 << " physvol @ " << (void*)hist->GetVolume(ind)
00400 << "\n";
00401 }
00402 warning() << endreq;
00403 }
00404
00405 verbose() << "Dumping TouchableHistory:\n";
00406 for (int ind=0; ind<hist->GetHistoryDepth(); ++ind) {
00407 verbose() << "\t (" << ind << ") " << hist->GetVolume(ind)->GetName()
00408 << " #" << hist->GetReplicaNumber(ind)
00409 << " physvol @ " << (void*)hist->GetVolume(ind)
00410 << "\n";
00411 }
00412 verbose() << endreq;
00413 #endif
00414
00415
00416 DayaBay::SimPmtHit* sphit = new DayaBay::SimPmtHit();
00417
00418
00419
00420
00421 sphit->setHitTime(preStepPoint->GetGlobalTime());
00422
00423
00424
00425 const G4AffineTransform& trans = hist->GetHistory()->GetTopTransform();
00426 const G4ThreeVector& global_pos = preStepPoint->GetPosition();
00427 G4ThreeVector pos = trans.TransformPoint(global_pos);
00428 sphit->setLocalPos(pos);
00429 sphit->setSensDetId(pmtid);
00430
00431
00432
00433 G4ThreeVector pol = trans.TransformAxis(track->GetPolarization());
00434 pol = pol.unit();
00435 G4ThreeVector dir = trans.TransformAxis(track->GetMomentum());
00436 dir = dir.unit();
00437 sphit->setPol(pol);
00438 sphit->setDir(dir);
00439 sphit->setWavelength(wavelength);
00440 sphit->setType(0);
00441
00442 sphit->setWeight(weight);
00443
00444
00445 #if 0
00446 debug() << "hit: id=" << (void*)pmtid << ", "
00447 << wavelength/CLHEP::nm << " nm, "
00448 << "pol=[" << pol[0] << "," << pol[1] << "," << pol[2] << "] "
00449 << "pos=[" << pos[0] << "," << pos[1] << "," << pos[2] << "] "
00450 << endreq;
00451
00452 for (int ind=0; ind<hist->GetHistoryDepth(); ++ind) {
00453 verbose () << "\t (" << ind << ") " << hist->GetVolume(ind)->GetName()
00454 << " #" << hist->GetReplicaNumber(ind)
00455 << " physvol @ " << (void*)hist->GetVolume(ind)
00456 << "\n";
00457 }
00458 verbose() << endreq;
00459 #endif
00460
00461
00462 int trackid = track->GetTrackID();
00463 this->StoreHit(sphit,trackid);
00464
00465 return true;
00466 }
00467
00468 void DsPmtSensDet::StoreHit(DayaBay::SimPmtHit* hit, int trackid)
00469 {
00470 int did = hit->sensDetId();
00471 DayaBay::Detector det(did);
00472 short int sdid = det.siteDetPackedData();
00473
00474 G4DhHitCollection* hc = m_hc[sdid];
00475 if (!hc) {
00476 warning() << "Got hit with no hit collection. ID = " << (void*)did
00477 << " which is detector: \"" << DayaBay::Detector(did).detName()
00478 << "\". Storing to the " << collectionName[0] << " collection"
00479 << endreq;
00480 sdid = 0;
00481 hc = m_hc[sdid];
00482 }
00483
00484 #if 1
00485 verbose() << "Storing hit PMT: " << (void*)did
00486 << " from " << DayaBay::Detector(did).detName()
00487 << " in hc #"<< sdid << " = "
00488 << hit->hitTime()/CLHEP::ns << "[ns] "
00489 << hit->localPos()/CLHEP::cm << "[cm] "
00490 << hit->wavelength()/CLHEP::nm << "[nm]"
00491 << endreq;
00492 #endif
00493
00494 hc->insert(new G4DhHit(hit,trackid));
00495 }
00496
00497 void DsPmtSensDet::EndOfEvent(G4HCofThisEvent* hce)
00498 {
00499 debug() << "Cache has " << m_hc.size() << " collections" << endreq;
00500
00501 int ncols = hce->GetNumberOfCollections();
00502 debug() << "DsPmtSensDet EndOfEvent " << ncols << " collections.";
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 int tothits = 0;
00513 for (int ind=0; ind<ncols; ++ind) {
00514 G4VHitsCollection* hc = hce->GetHC(ind);
00515 if ( hc->GetSize() > 0)
00516 {
00517 if ( tothits == 0) debug() << endreq;
00518 debug() << ind << ": "
00519 << hc->GetSDname() << "//" << hc->GetName() << " has "
00520 << hc->GetSize() << " hits" << endreq;
00521 }
00522 tothits += hc->GetSize() ;
00523 }
00524 if ( tothits == 0 ) debug() << " No hits found in " << ncols << " collections." << endreq;
00525 }