00001
00002
00003
00005 #include "SimG4CMS/Calo/interface/ECalSD.h"
00006 #include "SimG4Core/Notification/interface/TrackInformation.h"
00007 #include "Geometry/EcalCommonData/interface/EcalBarrelNumberingScheme.h"
00008 #include "Geometry/EcalCommonData/interface/EcalBaseNumber.h"
00009 #include "Geometry/EcalCommonData/interface/EcalEndcapNumberingScheme.h"
00010 #include "Geometry/EcalCommonData/interface/EcalPreshowerNumberingScheme.h"
00011 #include "Geometry/EcalCommonData/interface/ESTBNumberingScheme.h"
00012 #include "DetectorDescription/Core/interface/DDFilter.h"
00013 #include "DetectorDescription/Core/interface/DDFilteredView.h"
00014 #include "DetectorDescription/Core/interface/DDSolid.h"
00015 #include "DetectorDescription/Core/interface/DDSplit.h"
00016 #include "DetectorDescription/Core/interface/DDValue.h"
00017
00018 #include "Geometry/EcalCommonData/interface/EcalBaseNumber.h"
00019
00020 #include "G4LogicalVolumeStore.hh"
00021 #include "G4LogicalVolume.hh"
00022 #include "G4Step.hh"
00023 #include "G4Track.hh"
00024 #include "G4VProcess.hh"
00025
00026 ECalSD::ECalSD(G4String name, const DDCompactView & cpv,
00027 SensitiveDetectorCatalog & clg,
00028 edm::ParameterSet const & p, const SimTrackManager* manager) :
00029 CaloSD(name, cpv, clg, p, manager), numberingScheme(0) {
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 edm::ParameterSet m_EC = p.getParameter<edm::ParameterSet>("ECalSD");
00041 useBirk = m_EC.getParameter<bool>("UseBirkLaw");
00042 useBirkL3 = m_EC.getParameter<bool>("BirkL3Parametrization");
00043 birk1 = m_EC.getParameter<double>("BirkC1")*(g/(MeV*cm2));
00044 birk2 = m_EC.getParameter<double>("BirkC2");
00045 birk3 = m_EC.getParameter<double>("BirkC3");
00046 birkSlope = m_EC.getParameter<double>("BirkSlope");
00047 birkCut = m_EC.getParameter<double>("BirkCut");
00048 slopeLY = m_EC.getParameter<double>("SlopeLightYield");
00049 bool isItTB= m_EC.getUntrackedParameter<bool>("TestBeam", false);
00050 useWeight= true;
00051
00052 EcalNumberingScheme* scheme=0;
00053 if (name == "EcalHitsEB") scheme = dynamic_cast<EcalNumberingScheme*>(new EcalBarrelNumberingScheme());
00054 else if (name == "EcalHitsEE") scheme = dynamic_cast<EcalNumberingScheme*>(new EcalEndcapNumberingScheme());
00055 else if (name == "EcalHitsES") {
00056 if (isItTB) scheme = dynamic_cast<EcalNumberingScheme*>(new ESTBNumberingScheme());
00057 else scheme = dynamic_cast<EcalNumberingScheme*>(new EcalPreshowerNumberingScheme());
00058 useWeight = false;
00059 } else {edm::LogWarning("EcalSim") << "ECalSD: ReadoutName not supported\n";}
00060
00061 if (scheme) setNumberingScheme(scheme);
00062 LogDebug("EcalSim")
00063 << "Constructing a ECalSD with name " << GetName() << "\n";
00064 edm::LogInfo("EcalSim") << "ECalSD:: Use of Birks law is set to "
00065 << useBirk << " with three constants kB = "
00066 << birk1 << ", C1 = " << birk2 << ", C2 = " << birk3
00067 << "\n Use of L3 parametrization "
00068 << useBirkL3 << " with slope " << birkSlope
00069 << " and cut off " << birkCut << "\n"
00070 << " Slope for Light yield is set to "
00071 << slopeLY;
00072
00073 edm::LogInfo("EcalSim") << "ECalSD:: Suppression Flag " << suppressHeavy
00074 << " protons below " << kmaxProton << " MeV,"
00075 << " neutrons below " << kmaxNeutron << " MeV and"
00076 << " ions below " << kmaxIon << " MeV";
00077
00078 if (useWeight) initMap(name,cpv);
00079
00080 }
00081
00082 ECalSD::~ECalSD() {
00083 if (numberingScheme) delete numberingScheme;
00084 }
00085
00086 double ECalSD::getEnergyDeposit(G4Step * aStep) {
00087
00088 if (aStep == NULL) {
00089 return 0;
00090 } else {
00091 preStepPoint = aStep->GetPreStepPoint();
00092 G4String nameVolume = preStepPoint->GetPhysicalVolume()->GetName();
00093
00094
00095 double weight = 1.;
00096 if (suppressHeavy) {
00097 G4Track* theTrack = aStep->GetTrack();
00098 TrackInformation * trkInfo = (TrackInformation *)(theTrack->GetUserInformation());
00099 if (trkInfo) {
00100 int pdg = theTrack->GetDefinition()->GetPDGEncoding();
00101 if (!(trkInfo->isPrimary())) {
00102 double ke = theTrack->GetKineticEnergy()/MeV;
00103 if (((pdg/1000000000 == 1 && ((pdg/10000)%100) > 0 &&
00104 ((pdg/10)%100) > 0)) && (ke<kmaxIon)) weight = 0;
00105 if ((pdg == 2212) && (ke < kmaxProton)) weight = 0;
00106 if ((pdg == 2112) && (ke < kmaxNeutron)) weight = 0;
00107 if (weight == 0) {
00108 LogDebug("EcalSim") << "Ignore Track " << theTrack->GetTrackID()
00109 << " Type " << theTrack->GetDefinition()->GetParticleName()
00110 << " Kinetic Energy " << ke << " MeV";
00111 }
00112 }
00113 }
00114 }
00115 if (useWeight) {
00116 weight *= curve_LY(aStep);
00117 if (useBirk) {
00118 if (useBirkL3) weight *= getBirkL3(aStep);
00119 else weight *= getAttenuation(aStep, birk1, birk2, birk3);
00120 }
00121 }
00122 double edep = aStep->GetTotalEnergyDeposit() * weight;
00123 LogDebug("EcalSim") << "ECalSD:: " << nameVolume
00124 <<" Light Collection Efficiency " << weight
00125 << " Weighted Energy Deposit " << edep/MeV << " MeV";
00126 return edep;
00127 }
00128 }
00129
00130 int ECalSD::getRadiationLenght(G4Step * aStep) {
00131
00132 if (aStep == NULL) {
00133 return 0;
00134 } else {
00135
00136 G4ThreeVector hitPoint = aStep->GetPreStepPoint()->GetPosition();
00137 G4VPhysicalVolume* currentPV = aStep->GetPreStepPoint()->GetPhysicalVolume();
00138 G4String name = currentPV->GetName();
00139 std::string crystal;
00140 crystal.assign(name,0,4);
00141
00142 int thisX0 = 0;
00143 if (crystal == "EFRY"){
00144 float z = hitPoint.z();
00145 float detz = fabs(fabs(z)-3200);
00146 thisX0 = (int)floor( detz/8.9 );
00147 }
00148 if(crystal == "EBRY") {
00149 float x = hitPoint.x();
00150 float y = hitPoint.y();
00151 float r = sqrt(x*x +y*y);
00152 float detr = r -1290;
00153 thisX0 = (int)floor( detr/8.9);
00154 }
00155
00156 return thisX0;
00157 }
00158 }
00159
00160 uint32_t ECalSD::setDetUnitId(G4Step * aStep) {
00161 getBaseNumber(aStep);
00162 return (numberingScheme == 0 ? 0 : numberingScheme->getUnitID(theBaseNumber));
00163 }
00164
00165 void ECalSD::setNumberingScheme(EcalNumberingScheme* scheme) {
00166 if (scheme != 0) {
00167 edm::LogInfo("EcalSim") << "EcalSD: updates numbering scheme for "
00168 << GetName() << "\n";
00169 if (numberingScheme) delete numberingScheme;
00170 numberingScheme = scheme;
00171 }
00172 }
00173
00174 void ECalSD::initMap(G4String sd, const DDCompactView & cpv) {
00175
00176 G4String attribute = "ReadOutName";
00177 DDSpecificsFilter filter;
00178 DDValue ddv(attribute,sd,0);
00179 filter.setCriteria(ddv,DDSpecificsFilter::equals);
00180 DDFilteredView fv(cpv);
00181 fv.addFilter(filter);
00182 fv.firstChild();
00183
00184 const G4LogicalVolumeStore * lvs = G4LogicalVolumeStore::GetInstance();
00185 std::vector<G4LogicalVolume *>::const_iterator lvcite;
00186 bool dodet=true;
00187 while (dodet) {
00188 const DDSolid & sol = fv.logicalPart().solid();
00189 const std::vector<double> & paras = sol.parameters();
00190 G4String name = DDSplit(sol.name()).first;
00191 G4LogicalVolume* lv=0;
00192 for (lvcite = lvs->begin(); lvcite != lvs->end(); lvcite++)
00193 if ((*lvcite)->GetName() == name) {
00194 lv = (*lvcite);
00195 break;
00196 }
00197 LogDebug("EcalSim") << "ECalSD::initMap (for " << sd << "): Solid " << name
00198 << " Shape " << sol.shape() << " Parameter 0 = "
00199 << paras[0] << " Logical Volume " << lv;
00200 if (sol.shape() == ddtrap) {
00201 double dz = 2*paras[0];
00202 xtalLMap.insert(std::pair<G4LogicalVolume*,double>(lv,dz));
00203 }
00204 dodet = fv.next();
00205 }
00206 LogDebug("EcalSim") << "ECalSD: Length Table for " << attribute << " = "
00207 << sd << ":";
00208 std::map<G4LogicalVolume*,double>::const_iterator ite = xtalLMap.begin();
00209 int i=0;
00210 for (; ite != xtalLMap.end(); ite++, i++) {
00211 G4String name = "Unknown";
00212 if (ite->first != 0) name = (ite->first)->GetName();
00213 LogDebug("EcalSim") << " " << i << " " << ite->first << " " << name
00214 << " L = " << ite->second;
00215 }
00216 }
00217
00218 double ECalSD::curve_LY(G4Step* aStep) {
00219
00220 G4StepPoint* stepPoint = aStep->GetPreStepPoint();
00221 G4LogicalVolume* lv = stepPoint->GetTouchable()->GetVolume(0)->GetLogicalVolume();
00222 G4String nameVolume= lv->GetName();
00223
00224 double weight = 1.;
00225 G4ThreeVector localPoint = setToLocal(stepPoint->GetPosition(),
00226 stepPoint->GetTouchable());
00227 double crlength = crystalLength(lv);
00228 double dapd = 0.5 * crlength - localPoint.z();
00229 if (dapd >= -0.1 || dapd <= crlength+0.1) {
00230 if (dapd <= 100.)
00231 weight = 1.0 + slopeLY - dapd * 0.01 * slopeLY;
00232 } else {
00233 edm::LogWarning("EcalSim") << "ECalSD: light coll curve : wrong distance "
00234 << "to APD " << dapd << " crlength = "
00235 << crlength << " crystal name = " << nameVolume
00236 << " z of localPoint = " << localPoint.z()
00237 << " take weight = " << weight;
00238 }
00239 LogDebug("EcalSim") << "ECalSD, light coll curve : " << dapd
00240 << " crlength = " << crlength
00241 << " crystal name = " << nameVolume
00242 << " z of localPoint = " << localPoint.z()
00243 << " take weight = " << weight;
00244 return weight;
00245 }
00246
00247 double ECalSD::crystalLength(G4LogicalVolume* lv) {
00248
00249 double length= 230.;
00250 std::map<G4LogicalVolume*,double>::const_iterator ite = xtalLMap.find(lv);
00251 if (ite != xtalLMap.end()) length = ite->second;
00252 return length;
00253 }
00254
00255 void ECalSD::getBaseNumber(const G4Step* aStep) {
00256
00257 theBaseNumber.reset();
00258 const G4VTouchable* touch = aStep->GetPreStepPoint()->GetTouchable();
00259 int theSize = touch->GetHistoryDepth()+1;
00260 if ( theBaseNumber.getCapacity() < theSize ) theBaseNumber.setSize(theSize);
00261
00262 if ( theSize > 1 ) {
00263 for (int ii = 0; ii < theSize ; ii++) {
00264 theBaseNumber.addLevel(touch->GetVolume(ii)->GetName(),touch->GetReplicaNumber(ii));
00265 LogDebug("EcalSim") << "ECalSD::getBaseNumber(): Adding level " << ii
00266 << ": " << touch->GetVolume(ii)->GetName() << "["
00267 << touch->GetReplicaNumber(ii) << "]";
00268 }
00269 }
00270
00271 }
00272
00273 double ECalSD::getBirkL3(G4Step* aStep) {
00274
00275 double weight = 1.;
00276 double charge = aStep->GetPreStepPoint()->GetCharge();
00277
00278 if (charge != 0. && aStep->GetStepLength() > 0) {
00279 G4Material* mat = aStep->GetPreStepPoint()->GetMaterial();
00280 double density = mat->GetDensity();
00281 double dedx = aStep->GetTotalEnergyDeposit()/aStep->GetStepLength();
00282 double rkb = birk1/density;
00283 weight = 1. - birkSlope*log(rkb*dedx);
00284 if (weight < birkCut) weight = birkCut;
00285 else if (weight > 1.) weight = 1.;
00286 LogDebug("EcalSim") << "ECalSD::getBirkL3 in " << mat->GetName()
00287 << " Charge " << charge << " dE/dx " << dedx
00288 << " Birk Const " << rkb << " Weight = " << weight
00289 << " dE " << aStep->GetTotalEnergyDeposit();
00290 }
00291 return weight;
00292
00293 }