diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/cmt/requirements b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/cmt/requirements new file mode 100644 index 0000000000000000000000000000000000000000..ed274ba39c4f84c80205e4f1bf3e6cae5a730336 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/cmt/requirements @@ -0,0 +1,35 @@ +package MuonFastDigitization + +public +use AtlasPolicy AtlasPolicy-* + +private +use AtlasCLHEP AtlasCLHEP-* External +use AtlasROOT AtlasROOT-* External +use GaudiInterface GaudiInterface-* External + +use StoreGate StoreGate-* Control +use AthenaKernel AthenaKernel-* Control +use AthenaBaseComps AthenaBaseComps-* Control + +use Identifier Identifier-* DetectorDescription + +use MuonIdHelpers MuonIdHelpers-* MuonSpectrometer +use MuonSimEvent MuonSimEvent-* MuonSpectrometer +use MuonSimData MuonSimData-* MuonSpectrometer +use MuonReadoutGeometry MuonReadoutGeometry-* MuonSpectrometer/MuonDetDescr +use MuonPrepRawData MuonPrepRawData-* MuonSpectrometer/MuonReconstruction/MuonRecEvent +use TrkEventPrimitives TrkEventPrimitives-* Tracking/TrkEvent +use TrkSurfaces TrkSurfaces-* Tracking/TrkDetDescr +use MuonRecToolInterfaces MuonRecToolInterfaces-* MuonSpectrometer/MuonReconstruction/MuonRecTools +use PathResolver PathResolver-* Tools + + +public +library MuonFastDigitization *.cxx components/*.cxx +apply_pattern component_library + +#private +#macro cppdebugflags '$(cppdebugflags_s)' +#macro_remove componentshr_linkopts "-Wl,-s" + diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/MM_FastDigitizer.cxx b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/MM_FastDigitizer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4b63f026026fc0bd44a849b816e01e49a06ab179 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/MM_FastDigitizer.cxx @@ -0,0 +1,552 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//Gaudi - Core +#include "StoreGate/StoreGateSvc.h" + +//Inputs +#include "MuonSimData/MuonSimDataCollection.h" +#include "MuonSimData/MuonSimData.h" + +//Outputs +#include "MuonPrepRawData/MMPrepDataContainer.h" +#include "MuonPrepRawData/MMPrepData.h" + +#include "MM_FastDigitizer.h" +#include "MuonSimEvent/MM_SimIdToOfflineId.h" +#include "MuonSimEvent/GenericMuonSimHitCollection.h" +#include "MuonSimEvent/MicromegasHitIdHelper.h" + +#include "MuonReadoutGeometry/NSWenumeration.h" +#include "MuonReadoutGeometry/NSWgeometry.h" +#include "MuonReadoutGeometry/MuonDetectorManager.h" +#include "MuonReadoutGeometry/MMReadoutElement.h" +#include "MuonIdHelpers/MmIdHelper.h" +#include "TrkEventPrimitives/LocalDirection.h" + +#include "Identifier/Identifier.h" +#include "TH1.h" +#include "TTree.h" +#include "TFile.h" + +//Random Numbers +#include "AthenaKernel/IAtRndmGenSvc.h" +#include "CLHEP/Random/RandGauss.h" + + +#include <string> +#include <sstream> +#include <iostream> +#include <fstream> + +using namespace Muon; +/*******************************************************************************/ + MM_FastDigitizer::MM_FastDigitizer(const std::string& name, ISvcLocator* pSvcLocator) +: AthAlgorithm(name, pSvcLocator) + , m_idHelperTool("Muon::MuonIdHelperTool/MuonIdHelperTool" ) + , m_muonClusterCreator("Muon::MuonClusterOnTrackCreator/MuonClusterOnTrackCreator") + , m_rndmSvc("AtRndmGenSvc", name ) + , m_inputObjectName("MicromegasSensitiveDetector") +{ + declareProperty("InputObjectName", m_inputObjectName = "MicromegasSensitiveDetector", "name of the input object"); + declareProperty("RndmEngine", m_rndmEngineName, "Random engine name"); + declareProperty("RndmSvc", m_rndmSvc, "Random Number Service used in Muon digitization"); + declareProperty("UseTimeShift", m_useTimeShift = true, "Use time shift"); + declareProperty("EnergyThreshold", m_energyThreshold = 50, "Minimal energy to produce a PRD" ); + declareProperty("CheckIds", m_checkIds = false, "Turn on validity checking of Identifiers" ); + declareProperty("MaskMultiplet", m_maskMultiplet = 0, "0: all, 1: first, 2: second, 3: both" ); +} +/*******************************************************************************/ +MM_FastDigitizer::~MM_FastDigitizer() { +} +/*******************************************************************************/ +StatusCode MM_FastDigitizer::initialize() { + StatusCode status(StatusCode::SUCCESS); + + // initialize transient event store + ATH_MSG_DEBUG ( "Retrieved StoreGateSvc." ); + + status = service("ActiveStoreSvc", m_activeStore); + if ( !status.isSuccess() ) { + ATH_MSG_FATAL ( "Could not get active store service" ); + return status; + } + + if( m_muonClusterCreator.retrieve().isFailure() ){ + ATH_MSG_WARNING("Failed to retrieve " << m_muonClusterCreator); + return StatusCode::FAILURE; + } + + + // initialize transient detector store and MuonGeoModel OR MuonDetDescrManager + StoreGateSvc* detStore=0; + m_detManager=0; + status = serviceLocator()->service("DetectorStore", detStore); + if (status.isSuccess()) { + if(detStore->contains<MuonGM::MuonDetectorManager>( "Muon" )){ + + status = detStore->retrieve(m_detManager); + if (status.isFailure()) { + ATH_MSG_FATAL ( "Could not retrieve MuonGeoModelDetectorManager!" ); + return status; + } + else { + ATH_MSG_DEBUG ( "Retrieved MuonGeoModelDetectorManager from StoreGate" ); + //initialize the MmIdHelper + m_idHelper = m_detManager->mmIdHelper(); + if(!m_idHelper) return status; + ATH_MSG_DEBUG ( "Retrieved MmIdHelper " << m_idHelper ); + } + } + } + else { + ATH_MSG_FATAL ( "Could not retrieve DetectorStore!" ); + return status; + } + + if( m_idHelperTool.retrieve().isFailure() ){ + ATH_MSG_WARNING("Failed to retrieve " << m_idHelperTool); + return StatusCode::FAILURE; + } + + // check the input object name + if (m_inputObjectName=="") { + ATH_MSG_FATAL ( "Property InputObjectName not set !" ); + return StatusCode::FAILURE; + } + else { + ATH_MSG_DEBUG ( "Input objects: '" << m_inputObjectName << "'" ); + } + + // getting our random numbers stream + ATH_MSG_DEBUG ( "Getting random number engine : <" << m_rndmEngineName << ">" ); + if (!m_rndmSvc.retrieve().isSuccess()){ + ATH_MSG_ERROR("Could not initialize Random Number Service"); + } + m_rndmEngine = m_rndmSvc->GetEngine(m_rndmEngineName); + if (m_rndmEngine==0) { + ATH_MSG_ERROR("Could not find RndmEngine : " << m_rndmEngineName ); + return StatusCode::FAILURE; + } + + + m_file = new TFile("MM_plots.root","RECREATE"); + m_ntuple = new TTree("a","a"); + m_ntuple->Branch("slx",&slx); + m_ntuple->Branch("sly",&sly); + m_ntuple->Branch("slz",&slz); + m_ntuple->Branch("dlx",&dlx); + m_ntuple->Branch("dly",&dly); + m_ntuple->Branch("dlz",&dlz); + m_ntuple->Branch("sulx",&sulx); + m_ntuple->Branch("suly",&suly); + m_ntuple->Branch("tsulx",&tsulx); + m_ntuple->Branch("tsuly",&tsuly); + m_ntuple->Branch("tsulz",&tsulz); + m_ntuple->Branch("stsulx",&stsulx); + m_ntuple->Branch("stsuly",&stsuly); + m_ntuple->Branch("stsulz",&stsulz); + m_ntuple->Branch("ang",&ang); + m_ntuple->Branch("shift",&shift); + m_ntuple->Branch("resx",&resx); + m_ntuple->Branch("resy",&resy); + m_ntuple->Branch("suresx",&suresx); + m_ntuple->Branch("suresy",&suresy); + m_ntuple->Branch("resz",&resz); + m_ntuple->Branch("err",&err); + m_ntuple->Branch("res",&res); + m_ntuple->Branch("pull",&pull); + m_ntuple->Branch("is",&is); + m_ntuple->Branch("seta",&seta); + m_ntuple->Branch("sphi",&sphi); + m_ntuple->Branch("sml",&sml); + m_ntuple->Branch("sl",&sl); + m_ntuple->Branch("ss",&ss); + m_ntuple->Branch("ieta",&ieta); + m_ntuple->Branch("iphi",&iphi); + m_ntuple->Branch("iml",&iml); + m_ntuple->Branch("il",&il); + m_ntuple->Branch("ich",&ich); + m_ntuple->Branch("istr",&istr); + m_ntuple->Branch("exitcode",&exitcode); + m_ntuple->Branch("mode",&mode); + m_ntuple->Branch("pdg",&pdg); + m_ntuple->Branch("trkid",&trkid); + m_ntuple->Branch("gpx",&gpx); + m_ntuple->Branch("gpy",&gpy); + m_ntuple->Branch("gpz",&gpz); + m_ntuple->Branch("gpr",&gpr); + m_ntuple->Branch("gpp",&gpp); + m_ntuple->Branch("dgpx",&dgpx); + m_ntuple->Branch("dgpy",&dgpy); + m_ntuple->Branch("dgpz",&dgpz); + m_ntuple->Branch("dgpr",&dgpr); + m_ntuple->Branch("dgpp",&dgpp); + m_ntuple->Branch("globalHitTime", &globalHitTime); + m_ntuple->Branch("tofCorrection", &tofCorrection); + m_ntuple->Branch("bunchTime", &bunchTime); + m_ntuple->Branch("e", &e); + m_ntuple->Branch("edep", &edep); + return StatusCode::SUCCESS; + +} +/*******************************************************************************/ +StatusCode MM_FastDigitizer::execute() { + + + + + // Create and record the SDO container in StoreGate + MuonSimDataCollection* sdoContainer = new MuonSimDataCollection(); + if (evtStore()->record(sdoContainer,"MM_SDO").isFailure()) { + ATH_MSG_ERROR ( "Unable to record MM SDO collection in StoreGate" ); + return StatusCode::FAILURE; + } + + MMPrepDataContainer* prdContainer = new MMPrepDataContainer(m_idHelper->detectorElement_hash_max()); + std::string key = "MM_Measurements"; + ATH_MSG_DEBUG(" Done! Total number of of MM chambers with PRDS: " << prdContainer->numberOfCollections() << " key " << key); + if (evtStore()->record(prdContainer,key).isFailure()) { + ATH_MSG_ERROR ( "Unable to record MMPrepData container in StoreGate" ); + return StatusCode::FAILURE; + } + + if( m_maskMultiplet == 3 ) { + + return StatusCode::SUCCESS; + } + // as the MMPrepDataContainer only allows const accesss, need a local vector as well. + std::vector<MMPrepDataCollection*> localMMVec(m_idHelper->detectorElement_hash_max()); + + const DataHandle< GenericMuonSimHitCollection > collGMSH; + if ( evtStore()->retrieve( collGMSH,m_inputObjectName ).isFailure()) { + ATH_MSG_WARNING("No MM hits found in SG"); + return StatusCode::FAILURE; + } + + ATH_MSG_DEBUG( "Retrieved " << collGMSH->size() << " MM hits!"); + + // Get the MicroMegas Id hit helper + MM_SimIdToOfflineId simToOffline(*m_idHelper); + + std::map<Identifier,int> hitsPerChannel; + int nhits = 0; + + GenericMuonSimHitCollection::const_iterator iterMM; + + const GenericMuonSimHit* previousHit = 0; + + for (iterMM=collGMSH->begin();iterMM!=collGMSH->end();++iterMM) { + const GenericMuonSimHit& hit = *iterMM; + + // SimHits without energy loss are not recorded. + // not needed because of already done in sensitive detector + // https://svnweb.cern.ch/trac/atlasoff/browser/MuonSpectrometer/MuonG4/MuonG4SD/trunk/src/MicromegasSensitiveDetector.cxx?rev=542333#L65 + // if(hit.depositEnergy()==0.) continue; + + if( previousHit && abs(hit.particleEncoding())==13 && abs(previousHit->particleEncoding())==13 ) { + Amg::Vector3D diff = previousHit->localPosition() - hit.localPrePosition(); + ATH_MSG_VERBOSE("second hit from a muon: prev " << previousHit->localPosition() << " current " << hit.localPrePosition() + << " diff " << diff ); + if( diff.mag() < 0.1 ) continue; + } + + globalHitTime = hit.globalpreTime(); + tofCorrection = hit.globalPosition().mag()/CLHEP::c_light; + bunchTime = globalHitTime - tofCorrection; + const float stripPropagationTime = 0.; + static const float jitter = 0.; + float MMDigitTime = bunchTime + jitter + stripPropagationTime; + + float timeWindowStrip = 120.; //driftvelocity gap; + if (MMDigitTime < -timeWindowStrip || MMDigitTime > timeWindowStrip) { + exitcode = 4; + m_ntuple->Fill(); + continue; + } + + // Read the information about the Micro Megas hit + ATH_MSG_VERBOSE("MM hit: r " << hit.globalPosition().perp() << " z " << hit.globalPosition().z() << " mclink " << hit.particleLink() ); + + // convert simHit id to offline layer id; make sanity checks; retrieve the associated detector element. + int simId = hit.GenericId(); + Identifier layid = simToOffline.convert(simId); + + // sanity checks + if( !m_idHelper->is_mm(layid) ){ + ATH_MSG_WARNING("MM id is not a mm id! " << m_idHelperTool->toString(layid)); + } + if( !m_idHelper->is_muon(layid) ){ + ATH_MSG_WARNING("MM id is not a muon id! " << m_idHelperTool->toString(layid)); + } + if( m_idHelper->is_mdt(layid)||m_idHelper->is_rpc(layid)||m_idHelper->is_tgc(layid)||m_idHelper->is_csc(layid)||m_idHelper->is_stgc(layid) ){ + ATH_MSG_WARNING("MM id has wrong technology type! " << m_idHelper->is_mdt(layid) << " " << m_idHelper->is_rpc(layid) + << " " << m_idHelper->is_tgc(layid) << " " << m_idHelper->is_csc(layid) << " " << m_idHelper->is_stgc(layid) ); + } + + // remove hits in masked multiplet + if( m_maskMultiplet == m_idHelperTool->stgcIdHelper().multilayer(layid) ) continue; + + // get readout element + const MuonGM::MMReadoutElement* detEl = m_detManager->getMMReadoutElement(layid); + if( !detEl ){ + ATH_MSG_WARNING("Failed to retrieve detector element for: " << m_idHelperTool->toString(layid) ); + continue; + } + + // collections stored per readout element + IdentifierHash hash; + m_idHelper->get_detectorElement_hash(layid, hash); + MuonPrepDataCollection<Muon::MMPrepData>* col = localMMVec[hash]; + if( !col ){ + col = new MMPrepDataCollection(hash); + col->setIdentifier(m_idHelper->channelID(m_idHelper->parentID(layid), m_idHelper->multilayer(layid),1,1) ); + if( prdContainer->addCollection(col,hash).isFailure() ){ + ATH_MSG_WARNING("Failed to add collection with hash " << (int)hash ); + delete col;col=0; + continue; + } + localMMVec[hash] = col; + } + + // surface + const Trk::PlaneSurface& surf = detEl->surface(layid); + + //Angle + const Amg::Vector3D GloDire(hit.globalDirection().x(), hit.globalDirection().y(), hit.globalDirection().z()); + Trk::LocalDirection locDire; + surf.globalToLocalDirection(GloDire, locDire); + float inAngle_XZ = fabs( locDire.angleXZ() / CLHEP::degree); + inAngle_XZ = 90. - inAngle_XZ ; + + // compute hit position within the detector element/surfaces + Amg::Transform3D gToL = detEl->absTransform().inverse(); + Amg::Vector3D hpos(hit.globalPosition().x(),hit.globalPosition().y(),hit.globalPosition().z()); + Amg::Vector3D lpos = gToL*hpos; + Amg::Vector3D slpos = surf.transform().inverse()*hpos; + + Amg::Vector3D ldir; + if (MM_READOUT[m_idHelper->gasGap(layid)-1]==1) + ldir = surf.transform().inverse().linear()*Amg::Vector3D(hit.globalDirection().x(), hit.globalDirection().y(), hit.globalDirection().z()); + else + ldir = surf.transform().inverse().linear()*Amg::Vector3D(hit.globalDirection().x(), hit.globalDirection().y(), -hit.globalDirection().z()); + + double scale;//, scaletop; +// double gasgap = 5.; + + scale = -slpos.z()/ldir.z(); +// scaletop = (gasgap+slpos.z())/ldir.z(); + + Amg::Vector3D hitOnSurface = slpos + scale*ldir; +// Amg::Vector3D hitOnTopSurface = slpos + scaletop*ldir; + + // account for time offset + const double vdrift = 0.047; + double shiftTimeOffset = MMDigitTime*vdrift; + Amg::Vector3D hitAfterTimeShift(hitOnSurface.x(),hitOnSurface.y(),shiftTimeOffset); + Amg::Vector3D hitAfterTimeShiftOnSurface = hitAfterTimeShift - (shiftTimeOffset/ldir.z())*ldir; + + // resolution = -.01/3 * angle + .64/3. + double resolution; + if (fabs(inAngle_XZ)<3) + resolution = .07; + else + resolution = ( -.001/3.*fabs(inAngle_XZ) ) + .28/3.; + double sp = CLHEP::RandGauss::shoot(m_rndmEngine, 0, resolution); + + ATH_MSG_VERBOSE("slpos.z " << slpos.z() << ", ldir " << ldir.z() << ", scale " << scale << ", hitOnSurface.z " << hitOnSurface.z() ); + + if( fabs(hitOnSurface.z()) > 0.1 ) ATH_MSG_WARNING("bad propagation to surface " << hitOnSurface ); + if( fabs(hitAfterTimeShiftOnSurface.z()) > 0.1 ) ATH_MSG_WARNING("bad propagation to surface after time shift " << hitAfterTimeShiftOnSurface ); + // smeared local position + Amg::Vector2D posOnSurf(hitOnSurface.x()+sp,hitOnSurface.y()); + +// int digiMode = 0; + // for large angles project perpendicular to surface + if( fabs(inAngle_XZ) > 70 ){ + posOnSurf[0]=(slpos.x()+sp); +// digiMode = 1; + // if using timing information use hit position after shift + }else if( m_useTimeShift ){ + posOnSurf[0]=(hitAfterTimeShiftOnSurface.x()+sp); +// digiMode = 2; + } + + ////// fill first part of ntuple + Amg::Vector3D repos = detEl->globalPosition(); + MicromegasHitIdHelper* hitHelper = MicromegasHitIdHelper::GetHelper(); + + std::string stName = m_idHelper->stationNameString(m_idHelper->stationName(layid)); + int isSmall = stName[2] == 'S'; + slx = hit.localPosition().x(); + sly = hit.localPosition().y(); + slz = hit.localPosition().z(); + dlx = lpos.x(); + dly = lpos.y(); + sulx = posOnSurf.x(); + suly = posOnSurf.y(); + tsulx = hitOnSurface.x(); + tsuly = hitOnSurface.y(); + tsulz = hitOnSurface.z(); + stsulx = hitAfterTimeShiftOnSurface.x(); + stsuly = hitAfterTimeShiftOnSurface.y(); + stsulz = hitAfterTimeShiftOnSurface.z(); + ang = inAngle_XZ; + shift = shiftTimeOffset; + resx = hit.localPosition().x() - lpos.x(); + resy = hit.localPosition().y() - lpos.y(); + resz = hit.localPosition().z() - lpos.z(); + suresx = posOnSurf.x()-hitOnSurface.x(); + suresy = posOnSurf.y()-hitOnSurface.y(); + err = -99999.; + res = -99999.; + pull = -99999.; + is = isSmall; + seta = hitHelper->GetZSector(simId); + sphi = hitHelper->GetPhiSector(simId); + sml = hitHelper->GetMultiLayer(simId); + sl = hitHelper->GetLayer(simId); + ss = hitHelper->GetSide(simId); + ieta = m_idHelper->stationEta(layid); + iphi = m_idHelper->stationPhi(layid); + iml = m_idHelper->multilayer(layid); + il = m_idHelper->gasGap(layid); + ich = -99999; + istr = -99999; + exitcode = 0; + mode = 0; + pdg = hit.particleEncoding(); + trkid = hit.trackNumber(); + gpx = hit.globalPosition().x(); + gpy = hit.globalPosition().y(); + gpz = hit.globalPosition().z(); + gpr = hit.globalPosition().perp(); + gpp = hit.globalPosition().phi(); + dgpx = repos.x(); + dgpy = repos.y(); + dgpz = repos.z(); + dgpr = repos.perp(); + dgpp = repos.phi(); + edep = hit.depositEnergy(); + e = hit.kineticEnergy(); + + + ///// + if(hit.kineticEnergy()<m_energyThreshold && abs(hit.particleEncoding())==11) { + exitcode = 5; + m_ntuple->Fill(); + continue; + } + + // perform bound check + if( !surf.insideBounds(posOnSurf) ){ + exitcode = 1; + m_ntuple->Fill(); + continue; + } + + // recalculate strip number after smearing + int stripNumber = detEl->stripNumber(posOnSurf,layid); + //int LastStripNumber = detEl->stripNumber(posOnTopSurf, layid); + + if( stripNumber == -1 ){ + ATH_MSG_WARNING("Failed to obtain strip number " << m_idHelperTool->toString(layid) ); + ATH_MSG_WARNING(" pos " << posOnSurf << " z " << slpos.z() ); + exitcode = 2; + m_ntuple->Fill(); + continue; + } + + // Recalculate the Identifier using the strip number + // here need to use parent ID to avoid creating corrupted identifiers + Identifier parentID = m_idHelper->parentID(layid); + Identifier id = m_idHelper->channelID(parentID, m_idHelper->multilayer(layid), m_idHelper->gasGap(layid),stripNumber,m_checkIds); + + // only one hit per channel + int& counts = hitsPerChannel[id]; + ++counts; + if( counts > 1 ) continue; + ++nhits; + + + if( stripNumber >= detEl->numberOfStrips(layid) ){ + ATH_MSG_WARNING("Failed to obtain strip number " << m_idHelperTool->toString(layid) ); + ATH_MSG_WARNING(" pos " << posOnSurf << " z " << slpos.z() ); + exitcode = 3; + m_ntuple->Fill(); + continue; + } + + // Recalculate the Identifier using the strip number + // here need to use parent ID to avoid creating corrupted identifiers + id = m_idHelper->channelID(parentID, m_idHelper->multilayer(layid), m_idHelper->gasGap(layid),stripNumber,m_checkIds); + + if( stripNumber != m_idHelper->channel(id) ) { + ATH_MSG_WARNING(" bad stripNumber: in " << stripNumber << " from id " << m_idHelper->channel(id)); + exitcode = 4; + continue; + } + + std::vector<Identifier> rdoList; + rdoList.push_back(id); + Amg::MatrixX cov(1,1); cov.setIdentity(); + cov *= resolution*resolution; + MMPrepData* prd = new MMPrepData( id,hash,posOnSurf,rdoList,&cov,detEl); + prd->setHashAndIndex(col->identifyHash(), col->size()); // <<< add this line to the MM code as well + col->push_back(prd); + // ATH_MSG_VERBOSE("Global hit: r " << hit.globalPosition().perp() << " phi " << hit.globalPosition().phi() << " z " << hit.globalPosition().z() + // << " detEl: r " << repos.perp() << " phi " << repos.phi() << " z " << repos.z() << " " << m_idHelper->print_to_string(id) ); + + // ATH_MSG_VERBOSE("Local hit: x " << hit.localPosition().x() << " y " << hit.localPosition().y() << " z " << hit.localPosition().z() + // << " detEl: x " << lpos.x() << " y " << lpos.y() << " z " << lpos.z() << " strip " << stripNumber); + ATH_MSG_DEBUG(" hit: " << m_idHelperTool->toString(id) << " hitx " << posOnSurf.x() << " residual " << posOnSurf.x() - hitOnSurface.x() + << " pull " << (posOnSurf.x() - hitOnSurface.x())/resolution ); + err = resolution; + ich = m_idHelper->channel(id); + istr = stripNumber; + +// const MuonClusterOnTrack* rot = m_muonClusterCreator->createRIO_OnTrack( *prd, hit.globalPosition() ); +// if( rot ){ +// res = rot->localParameters().get(Trk::locX)-hitOnSurface.x(); +// pull = res/rot->localErrorMatrix().error(Trk::locX); +// delete rot; +// } + + m_ntuple->Fill(); + // create SDO + MuonSimData::Deposit deposit(hit.particleLink(), MuonMCData(hitOnSurface.x(),hitOnSurface.y())); + //Record the SDO collection in StoreGate + std::vector<MuonSimData::Deposit> deposits; + deposits.push_back(deposit); + sdoContainer->insert ( std::make_pair ( id, MuonSimData(deposits,0) ) ); + // OLD CODE ENDS HERE + + previousHit = &hit; + } + + if( msgLvl(MSG::DEBUG) ){ + std::map<Identifier,int>::const_iterator hit = hitsPerChannel.begin(); + std::map<Identifier,int>::const_iterator hit_end = hitsPerChannel.end(); + msg(MSG::DEBUG) << " number of channels with hit " << hitsPerChannel.size() << " nhits " << nhits << std::endl; + for( ;hit!=hit_end;++hit ){ + msg(MSG::DEBUG) << " " << m_idHelperTool->toString(hit->first) << " -> " << hit->second << std::endl; + } + msg(MSG::DEBUG) << endreq; + } + return StatusCode::SUCCESS; +} +/*******************************************************************************/ +StatusCode MM_FastDigitizer::finalize() { + m_ntuple->Write(); + m_file->Write(); + m_file->Close(); + return StatusCode::SUCCESS; +} +/*******************************************************************************/ +/** Function to convert Radians into Degrees */ +float MM_FastDigitizer::RadsToDegrees(float Radians) +{ + float Degrees = Radians * (180.) / M_PI; + return Degrees; +} diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/MM_FastDigitizer.h b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/MM_FastDigitizer.h new file mode 100644 index 0000000000000000000000000000000000000000..8bdfbdf7ee0eeefc99481bda6dfd6d17da316ab3 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/MM_FastDigitizer.h @@ -0,0 +1,134 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef MUONDIGITIZATION_MM_FASTDIGITIZER_H +#define MUONDIGITIZATION_MM_FASTDIGITIZER_H + +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" +#include "StoreGate/StoreGateSvc.h" + +//Random +#include "CLHEP/Random/RandomEngine.h" +#include "AthenaKernel/IAtRndmGenSvc.h" +#include "CLHEP/Random/RandGauss.h" + +#include "MuonIdHelpers/MuonIdHelperTool.h" +#include "MuonRecToolInterfaces/IMuonClusterOnTrackCreator.h" + +class TTree; +class TFile; + +class MmIdHelper; +namespace MuonGM { + class MuonDetectorManager; +} + +//Random +namespace CLHEP{ + class HepRandomEngine; +} + + +class IAtRndmGenSvc; +class ActiveStoreSvc; + +class MM_FastDigitizer : public AthAlgorithm { + + public: + + MM_FastDigitizer(const std::string& name, ISvcLocator* pSvcLocator); + ~MM_FastDigitizer(); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + ServiceHandle<IAtRndmGenSvc> getRndmSvc() const { return m_rndmSvc; } // Random number service + CLHEP::HepRandomEngine *getRndmEngine() const { return m_rndmEngine; } // Random number engine used + + float RadsToDegrees(float Radians); + + private: + + ActiveStoreSvc* m_activeStore; + + const MuonGM::MuonDetectorManager* m_detManager; + const MmIdHelper* m_idHelper; + + TFile* m_file; + TTree* m_ntuple; + float slx; // local position simhit in G4 + float sly; + float slz; + float dlx; // local position simhit in GeoModel frame + float dly; + float dlz; + float sulx; // local position from REin tracking surface frame + float suly; + float tsulx; // local position simhit in tracking surface frame + float tsuly; + float tsulz; + float stsulx; // local position simhit in tracking surface frame + float stsuly; + float stsulz; + float ang; // local angel + float shift; // shift due to bunch offset + float resx; // residuals in local G4 - GeoModel + float resy; + float resz; + float suresx; // residuals g4 - RE stripPosition in tracking frame + float suresy; + float err; // error + float res; // residual + pull + float pull; + int is; // simulation Identifier: issmall + int seta; // eta + int sphi; // phi + int sml; // multi layer + int sl; // layer + int ss; // strip + int ieta; // offline id fields + int iphi; + int iml; + int il; + int ich; // strip number of Id + int istr; // strip number from RE + int exitcode; // flag reason why prd not made + int mode; // flag digitization strategy + int pdg; // pdg ID + int trkid; // track number in G4 + float gpx; // global position of the simhit + float gpy; + float gpz; + float gpr; // radial position pos.perp() + float gpp; // phi position pos.phi() + float dgpx; // same for readout element center + float dgpy; + float dgpz; + float dgpr; + float dgpp; + float tofCorrection; + float bunchTime; + float globalHitTime; + float e; + float edep; + + protected: + ToolHandle <Muon::MuonIdHelperTool> m_idHelperTool; + ToolHandle <Muon::IMuonClusterOnTrackCreator> m_muonClusterCreator; + ServiceHandle <IAtRndmGenSvc> m_rndmSvc; // Random number service + CLHEP::HepRandomEngine *m_rndmEngine; // Random number engine used - not init in SiDigitization + std::string m_rndmEngineName;// name of random engine + std::string m_inputObjectName; // name of the input objects + bool m_useTimeShift; + double m_energyThreshold; + bool m_checkIds; + int m_maskMultiplet; +}; + +#endif // MUONDIGITIZATION_MM_DIGITIZER_H + + diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/components/MuonFastDigitization_entries.cxx b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/components/MuonFastDigitization_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2fba763438624bbb56fbdd46af7d15fa38b54f52 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/components/MuonFastDigitization_entries.cxx @@ -0,0 +1,12 @@ +#include "GaudiKernel/DeclareFactoryEntries.h" +#include "../sTgcFastDigitizer.h" +#include "../MM_FastDigitizer.h" +#include "AthenaKernel/IAtRndmGenSvc.h" + +DECLARE_ALGORITHM_FACTORY( sTgcFastDigitizer ) +DECLARE_ALGORITHM_FACTORY( MM_FastDigitizer ) + +DECLARE_FACTORY_ENTRIES(MuonFastDigitization) { + DECLARE_ALGORITHM( sTgcFastDigitizer ) + DECLARE_ALGORITHM( MM_FastDigitizer ) +} diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/components/MuonFastDigitization_load.cxx b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/components/MuonFastDigitization_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c436585549612e5641d7c83944d562f4524e5c19 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/components/MuonFastDigitization_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(MuonFastDigitization) diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/sTgcFastDigitizer.cxx b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/sTgcFastDigitizer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a6d330d5b6995ddd6386834a37e8c177339b8f55 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/sTgcFastDigitizer.cxx @@ -0,0 +1,674 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "sTgcFastDigitizer.h" +#include "MuonSimEvent/sTgcSimIdToOfflineId.h" + +#include "MuonSimEvent/GenericMuonSimHitCollection.h" + +#include "MuonSimEvent/MicromegasHitIdHelper.h" +#include "MuonReadoutGeometry/MuonDetectorManager.h" +#include "MuonReadoutGeometry/sTgcReadoutElement.h" +#include "MuonIdHelpers/sTgcIdHelper.h" + +#include "MuonSimData/MuonSimDataCollection.h" +#include "MuonSimData/MuonSimData.h" +#include "MuonPrepRawData/sTgcPrepDataContainer.h" +#include "MuonPrepRawData/sTgcPrepData.h" +#include "TrkEventPrimitives/LocalDirection.h" +#include "TrkSurfaces/Surface.h" + +#include "Identifier/Identifier.h" +#include "TH1.h" +#include "TTree.h" +#include "TFile.h" + +//Random Numbers +#include "AthenaKernel/IAtRndmGenSvc.h" +#include "CLHEP/Random/RandGauss.h" +#include "CLHEP/Random/RandFlat.h" +#include "PathResolver/PathResolver.h" + +using namespace Muon; + +sTgcFastDigitizer::sTgcFastDigitizer(const std::string& name, ISvcLocator* pSvcLocator) + : AthAlgorithm(name, pSvcLocator) + , m_idHelperTool("Muon::MuonIdHelperTool/MuonIdHelperTool" ) + , m_muonClusterCreator("Muon::MuonClusterOnTrackCreator/MuonClusterOnTrackCreator") + , m_rndmSvc("AtRndmGenSvc", name ) + , m_timeWindowOffsetWire(0.) + , m_timeWindowOffsetStrip(0.) + , m_timeWindowWire(24.95) // TGC 29.32; // 29.32 ns = 26 ns + 4 * 0.83 ns + , m_timeWindowStrip(24.95) // TGC 40.94; // 40.94 ns = 26 ns + 18 * 0.83 ns + , m_bunchCrossingTime(24.95) // 24.95 ns =(40.08 MHz)^(-1) +{ + declareProperty("IdHelperTool", m_idHelperTool); + declareProperty("ClusterCreator", m_muonClusterCreator); + declareProperty("ChannelTypes", m_channelTypes = 3); + declareProperty("RndmEngine", m_rndmEngineName, "Random engine name"); + declareProperty("RndmSvc", m_rndmSvc, "Random Number Service used in Muon digitization"); + declareProperty("EnergyThreshold", m_energyThreshold = 50, "Minimal energy of incoming particle to produce a PRD" ); + declareProperty("EnergyDepositThreshold", m_energyDepositThreshold = 0.00052, "Minimal energy deposit to produce a PRD" ); + declareProperty("CheckIds", m_checkIds = false, "Turn on validity checking of Identifiers" ); +} + +sTgcFastDigitizer::~sTgcFastDigitizer() { + +} + +StatusCode sTgcFastDigitizer::initialize() { + + if ( detStore()->retrieve( m_detManager ).isFailure()) { + ATH_MSG_WARNING("Failed to retrieve MuonDetectorManager"); + return StatusCode::FAILURE; + } + if( detStore()->retrieve( m_idHelper ).isFailure() ){ + ATH_MSG_WARNING("Failed to retrieve sTgcIdHelper"); + return StatusCode::FAILURE; + } + m_rndmEngine = m_rndmSvc->GetEngine(m_rndmEngineName); + if (m_rndmEngine==0) { + ATH_MSG_ERROR("Could not find RndmEngine : " << m_rndmEngineName ); + return StatusCode::FAILURE; + } + if( m_idHelperTool.retrieve().isFailure() ){ + ATH_MSG_WARNING("Failed to retrieve " << m_idHelperTool); + return StatusCode::FAILURE; + } + + if( m_muonClusterCreator.retrieve().isFailure() ){ + ATH_MSG_WARNING("Failed to retrieve " << m_muonClusterCreator); + return StatusCode::FAILURE; + } + + if( !readFileOfTimeJitter() ) return StatusCode::FAILURE; + + m_file = new TFile("sTgcplots.root","RECREATE"); + + m_ntuple = new TTree("a","a"); + m_ntuple->Branch("slx",&slx); + m_ntuple->Branch("sly",&sly); + m_ntuple->Branch("slz",&slz); + m_ntuple->Branch("dlx",&dlx); + m_ntuple->Branch("dly",&dly); + m_ntuple->Branch("dlz",&dlz); + m_ntuple->Branch("sulx",&sulx); + m_ntuple->Branch("suly",&suly); + m_ntuple->Branch("tsulx",&tsulx); + m_ntuple->Branch("tsuly",&tsuly); + m_ntuple->Branch("tsulz",&tsulz); + m_ntuple->Branch("resx",&resx); + m_ntuple->Branch("resy",&resy); + m_ntuple->Branch("suresx",&suresx); + m_ntuple->Branch("suresy",&suresy); + m_ntuple->Branch("resz",&resz); + m_ntuple->Branch("errx",&errx); + m_ntuple->Branch("erry",&erry); + m_ntuple->Branch("res",&res); + m_ntuple->Branch("pull",&pull); + m_ntuple->Branch("is",&is); + m_ntuple->Branch("seta",&seta); + m_ntuple->Branch("sphi",&sphi); + m_ntuple->Branch("sml",&sml); + m_ntuple->Branch("sl",&sl); + m_ntuple->Branch("ss",&ss); + m_ntuple->Branch("stype",&stype); + m_ntuple->Branch("ieta",&ieta); + m_ntuple->Branch("iphi",&iphi); + m_ntuple->Branch("iml",&iml); + m_ntuple->Branch("il",&il); + m_ntuple->Branch("ich",&ich); + m_ntuple->Branch("istr",&istr); + m_ntuple->Branch("itype",&itype); + m_ntuple->Branch("ipadeta",&ipadeta); + m_ntuple->Branch("ipadphi",&ipadphi); + m_ntuple->Branch("exitcode",&exitcode); + m_ntuple->Branch("mode",&mode); + m_ntuple->Branch("pdg",&pdg); + m_ntuple->Branch("trkid",&trkid); + m_ntuple->Branch("bct",&bct); + m_ntuple->Branch("tb",&tb); + m_ntuple->Branch("tj",&tj); + m_ntuple->Branch("tg4",&tg4); + m_ntuple->Branch("ttof",&ttof); + m_ntuple->Branch("gpx",&gpx); + m_ntuple->Branch("gpy",&gpy); + m_ntuple->Branch("gpz",&gpz); + m_ntuple->Branch("gpr",&gpr); + m_ntuple->Branch("gpp",&gpp); + m_ntuple->Branch("dgpx",&dgpx); + m_ntuple->Branch("dgpy",&dgpy); + m_ntuple->Branch("dgpz",&dgpz); + m_ntuple->Branch("dgpr",&dgpr); + m_ntuple->Branch("dgpp",&dgpp); + m_ntuple->Branch("edep",&edep); + m_ntuple->Branch("e",&e); + m_ntuple->Branch("at",&at); + m_ntuple->Branch("as",&as); + + return StatusCode::SUCCESS; + +} + +StatusCode sTgcFastDigitizer::execute() { + +// Create and record the SDO container in StoreGate + MuonSimDataCollection* sdoContainer = new MuonSimDataCollection(); + if (evtStore()->record(sdoContainer,"STGC_SDO").isFailure()) { + ATH_MSG_ERROR ( "Unable to record sTgc SDO collection in StoreGate" ); + return StatusCode::FAILURE; + } + + sTgcPrepDataContainer* prdContainer = new sTgcPrepDataContainer(m_idHelper->detectorElement_hash_max()); + + // as the sTgcPrepDataContainer only allows const accesss, need a local vector as well. + std::vector<sTgcPrepDataCollection*> localsTgcVec(m_idHelper->detectorElement_hash_max()); + + const DataHandle< GenericMuonSimHitCollection > collGMSH; + if ( evtStore()->retrieve( collGMSH,"sTGCSensitiveDetector").isFailure()) { + ATH_MSG_WARNING("No sTgc hits found in SG"); + return StatusCode::FAILURE; + } + + ATH_MSG_DEBUG( "Retrieved " << collGMSH->size() << " sTgc hits!"); + sTgcHitIdHelper* hitHelper=sTgcHitIdHelper::GetHelper(); + sTgcSimIdToOfflineId simToOffline(*m_idHelper); + + const GenericMuonSimHit* previousHit = 0; + + std::map<Identifier,int> hitsPerChannel; + int nhits = 0; + GenericMuonSimHitCollection::const_iterator itersTgc; + for (itersTgc=collGMSH->begin();itersTgc!=collGMSH->end();++itersTgc) { + const GenericMuonSimHit& hit = *itersTgc; + + float globalHitTime = hit.globalpreTime(); + float tofCorrection = hit.globalPosition().mag()/CLHEP::c_light; + + // bunch time + float bunchTime = globalHitTime - tofCorrection; + + int simId = hit.GenericId(); + Identifier layid = simToOffline.convert(simId); + ATH_MSG_VERBOSE("sTgc hit: r " << hit.globalPosition().perp() << " z " << hit.globalPosition().z() << " mclink " << hit.particleLink() + << " -- " << m_idHelperTool->toString(layid)); + + std::string stName = m_idHelper->stationNameString(m_idHelper->stationName(layid)); + int isSmall = stName[2] == 'S'; + const MuonGM::sTgcReadoutElement* detEl = m_detManager->getsTgcReadoutElement(layid); + if( !detEl ){ + ATH_MSG_WARNING("Failed to retrieve detector element for: " << m_idHelperTool->toString(layid) ); + continue; + } + + IdentifierHash hash; + m_idHelper->get_detectorElement_hash(layid, hash); + MuonPrepDataCollection<Muon::sTgcPrepData>* col = localsTgcVec[hash]; + if( !col ){ + col = new sTgcPrepDataCollection(hash); + col->setIdentifier(m_idHelper->channelID(m_idHelper->parentID(layid), m_idHelper->multilayer(layid),1,1,1) ); + if( prdContainer->addCollection(col,hash).isFailure() ){ + ATH_MSG_WARNING("Failed to add collection with hash " << (int)hash ); + delete col;col=0; + continue; + } + localsTgcVec[hash] = col; + } + + Identifier parentId = m_idHelper->parentID(layid); + + // SimHits without energy loss are not recorded. + // not needed because of already done in sensitive detector + // https://svnweb.cern.ch/trac/atlasoff/browser/MuonSpectrometer/MuonG4/MuonG4SD/trunk/src/sTGCSensitiveDetector.cxx?rev=542333#L66 + // if(hit.depositEnergy()==0.) continue; + + + if( previousHit && abs(hit.particleEncoding())==13 && abs(previousHit->particleEncoding())==13 ) { + Amg::Vector3D diff = previousHit->localPosition() - hit.localPrePosition(); + if( diff.mag() < 0.1 ) { + ATH_MSG_VERBOSE("second hit from a muon: prev " << previousHit->localPosition() << " current " << hit.localPrePosition() + << " diff " << diff ); + continue; + } + } + + // select whether to produce only strips or strips + wires or strips + wires + pads + int ftype = m_channelTypes == 3 ? 0 : 1; + int ltype = m_channelTypes == 1 ? 1 : 2; + + for( int type=ftype;type<=ltype;++type ){ + + // only produce wire hits for outer two stations + if( type == 2 && abs(m_idHelper->stationEta(layid)) < 3 ) continue; + + // for debugging only treat pads + //if( type != 0 ) continue; + + // first create surface identifier + Identifier id = m_idHelper->channelID(parentId, m_idHelper->multilayer(layid), m_idHelper->gasGap(layid),type,1,m_checkIds); + ATH_MSG_VERBOSE("handling layer " << m_idHelperTool->toString(id) << " type " << type ); + const Trk::PlaneSurface& surf = detEl->surface(id); + Amg::Transform3D gToL = detEl->absTransform().inverse(); + Amg::Vector3D hpos(hit.globalPosition().x(),hit.globalPosition().y(),hit.globalPosition().z()); + Amg::Vector3D lpos = gToL*hpos; + Amg::Vector3D slpos = surf.transform().inverse()*hpos; + + // propagate sim hit position to surface + Amg::Vector3D ldir = surf.transform().inverse().linear()*Amg::Vector3D(hit.globalDirection().x(), hit.globalDirection().y(), hit.globalDirection().z()); //sleontsi + double scale = -slpos.z()/ldir.z(); + Amg::Vector3D hitOnSurface = slpos + scale*ldir; + + // the position resolution is depending on the incident angle + //double resolution = .18; + const Amg::Vector3D GloDire(hit.globalDirection().x(), hit.globalDirection().y(), hit.globalDirection().z()); + Trk::LocalDirection LocDirection; + surf.globalToLocalDirection(GloDire, LocDirection); + + float inAngle_time = 90 - fabs( LocDirection.angleXZ() / CLHEP::degree); + float inAngle_space = 90 - fabs( LocDirection.angleYZ() / CLHEP::degree); + if(inAngle_time > 90) inAngle_time = inAngle_time -90.; + if(inAngle_space > 90) inAngle_space = inAngle_space -90.; + + + + // bctagging +// static const float jitterInitial = 9999.; + float jitter = 0;//jitterInitial; // calculated at central strip but also used in all the strips fired by the same hit +// if(jitter > jitterInitial-0.1) { +// jitter = timeJitter(inAngle_time); +// } + + //const float stripPropagationTime = 3.3*CLHEP::ns/CLHEP::m * detEl->distanceToReadout(posOnSurf_strip, elemId); // 8.5*ns/m was used until MC10. + const float stripPropagationTime = 0.; // 8.5*ns/m was used until MC10. + + // shift by 0.5 to get all current bc in time + float sDigitTime = bunchTime + jitter + stripPropagationTime+0.5; + + uint16_t bctag = bcTagging(sDigitTime, type); + + // smear + // for the strips apply gaussian smearing, for the wire gangs or pads do nothing here + double sp = hitOnSurface.x(); + double resolution = 0; + if( type == 1 ){ + resolution = getResolution(inAngle_time); + sp = CLHEP::RandGauss::shoot(m_rndmEngine, hitOnSurface.x(), resolution); + } + //ATH_MSG_DEBUG("slpos.z " << slpos.z() << ", ldir " << ldir.z() << ", scale " << scale << ", hitOnSurface.z " << hitOnSurface.z()); + + + Amg::Vector2D posOnSurf(sp,hitOnSurface.y()); + Amg::Vector2D locHitPosOnSurf(hitOnSurface.x(),hitOnSurface.y()); + + /// now fill most of the ntuple + Amg::Vector3D repos = detEl->globalPosition(); + + slx = hit.localPosition().x(); + sly = hit.localPosition().y(); + slz = hit.localPosition().z(); + dlx = lpos.x(); + dly = lpos.y(); + dlz = lpos.z(); + sulx = posOnSurf.x(); + suly = posOnSurf.y(); + tsulx = hitOnSurface.x(); + tsuly = hitOnSurface.y(); + tsulz = hitOnSurface.z(); + resx = hit.localPosition().x() - lpos.x(); + resy = hit.localPosition().y() - lpos.y(); + resz = hit.localPosition().z() - lpos.z(); + suresx = posOnSurf.x()-hitOnSurface.x(); + suresy = posOnSurf.y()-hitOnSurface.y(); + errx = -99999.; + erry = -99999.; + res = -99999.; + pull = -99999.; + is = isSmall; + seta = hitHelper->GetZSector(simId); + sphi = hitHelper->GetPhiSector(simId); + sml = hitHelper->GetMultiLayer(simId); + sl = hitHelper->GetLayer(simId); + ss = hitHelper->GetSide(simId); + stype = type; + ieta = m_idHelper->stationEta(id); + iphi = m_idHelper->stationPhi(id); + iml = m_idHelper->multilayer(id); + il = m_idHelper->gasGap(id); + ich = -99999; + istr = -99999; + itype = -99999; + ipadeta = -99999; + ipadphi = -99999; + exitcode = 0; + mode = 0; + pdg = hit.particleEncoding(); + trkid = hit.trackNumber(); + bct = bctag; + tb = bunchTime; + tj = jitter; + tg4 = globalHitTime; + ttof = tofCorrection; + gpx = hit.globalPosition().x(); + gpy = hit.globalPosition().y(); + gpz = hit.globalPosition().z(); + gpr = hit.globalPosition().perp(); + gpp = hit.globalPosition().phi(); + dgpx = repos.x(); + dgpy = repos.y(); + dgpz = repos.z(); + dgpr = repos.perp(); + dgpp = repos.phi(); + edep = hit.depositEnergy(); + e = hit.kineticEnergy(); + at = inAngle_time; + as = inAngle_space; + // cut on the kineticEnergy = 50MeV + if(hit.kineticEnergy()< m_energyThreshold ) { + exitcode = 5; + m_ntuple->Fill(); + continue; + } + + // cut on depositEnergy(0.52KeV) to simulation the detector efficiency(95% for strips) + if( type ==1 && hit.depositEnergy()<m_energyDepositThreshold) { + ATH_MSG_VERBOSE("Drop SimHit with depositEnergy = " << edep << " in the strip response!"); + exitcode = 6; + m_ntuple->Fill(); + continue; + } + + /// done filling + if ( !surf.insideBounds(posOnSurf) ) { + exitcode = 1; + m_ntuple->Fill(); + continue; + } + + if(sDigitTime < -m_bunchCrossingTime+m_timeWindowOffsetStrip || +m_bunchCrossingTime+m_timeWindowOffsetStrip+ m_timeWindowStrip < sDigitTime) { + exitcode = 4; + m_ntuple->Fill(); + ATH_MSG_DEBUG( "Strip: Digitized time is outside of time window. " << sDigitTime + << " bunchTime: " << bunchTime << " time jitter: " << jitter + << " propagation time: " << stripPropagationTime ); + continue; + } + + bctag = bcTagging(sDigitTime, type); + + int stripNumber = detEl->stripNumber(locHitPosOnSurf,id); + if( stripNumber == -1 ){ + ATH_MSG_WARNING("Failed to obtain strip number " << m_idHelperTool->toString(id) + << " pos " << posOnSurf.x() << " - " << hitOnSurface.x() << " z " << slpos.z() << " type " << type ); + exitcode = 2; + m_ntuple->Fill(); + continue; + } + + // create channel identifier + id = m_idHelper->channelID(parentId, m_idHelper->multilayer(id), m_idHelper->gasGap(id),type,stripNumber,m_checkIds); + ATH_MSG_VERBOSE(" Unsmeared hit id " << m_idHelperTool->toString(id) ); + + int& counts = hitsPerChannel[id]; + ++counts; + if( counts > 1 ) continue; + ++nhits; + + + // recalculate using smeared position + stripNumber = detEl->stripNumber(posOnSurf,id); + if( stripNumber == -1 ){ + ATH_MSG_WARNING("Failed to obtain strip number " << m_idHelperTool->toString(id) + << " pos " << posOnSurf.x() << " - " << hitOnSurface.x() << " z " << slpos.z() << " type " << type ); + exitcode = 2; + m_ntuple->Fill(); + continue; + } + + // create channel identifier + id = m_idHelper->channelID(parentId, m_idHelper->multilayer(id), m_idHelper->gasGap(id),type,stripNumber,m_checkIds); + + if( type != m_idHelper->channelType(id) ) ATH_MSG_WARNING(" bad type: in " << type << " from id " << m_idHelper->channelType(id) + << " strip " << stripNumber << " from id " << m_idHelper->channel(id) + << " eta " << m_idHelper->stationEta(id) + << " local pos " << slpos ); + + // assign strip position to PRD for wires and pads + if( type != 1 ){ + Amg::Vector2D locpos(0,0); + if( !detEl->stripPosition(id,locpos ) ){ + ATH_MSG_WARNING("Failed to obtain local position for identifier " << m_idHelperTool->toString(id) ); + exitcode = 3; + m_ntuple->Fill(); + continue; + } + posOnSurf = locpos; + } + + std::vector<Identifier> rdoList; + rdoList.push_back(id); + + double errX = 500; + + if( type == 2 ){ + const MuonGM::MuonChannelDesign* design = detEl->getDesign(id); + if( !design ){ + ATH_MSG_WARNING("Failed to get design for " << m_idHelperTool->toString(id) ); + }else{ + errX = fabs(design->inputPitch)/sqrt(12); + } + }else if( type == 1 ){ + errX = resolution; + } + if( type == 0 ){ + + const MuonGM::MuonPadDesign* design = detEl->getPadDesign(id); + if( !design ){ + ATH_MSG_WARNING("Failed to get design for " << m_idHelperTool->toString(id) ); + }else{ + errX = design->channelWidth(posOnSurf,true)/sqrt(12); + } + } + + + Amg::MatrixX cov(1,1); cov.setIdentity(); + cov*=errX*errX; + +// ATH_MSG_DEBUG(" New hit " << m_idHelperTool->toString(id) << " chtype " << type << " lpos " << posOnSurf << " from truth " +// << hitOnSurface << " error " << locErrMat->error(Trk::locX) << " pull " << (posOnSurf.x()-hitOnSurface.x())/locErrMat->error(Trk::locX) ); + + //sTgcPrepData* prd = new sTgcPrepData( id,hash,posOnSurf,rdoList,locErrMat,detEl); + sTgcPrepData* prd = new sTgcPrepData( id,hash,posOnSurf,rdoList,&cov,detEl, bctag); + prd->setHashAndIndex(col->identifyHash(), col->size()); + col->push_back(prd); + + /// fill final bits of the ntuple + suresx = posOnSurf.x()-hitOnSurface.x(); + suresy = posOnSurf.y()-hitOnSurface.y(); + sulx = posOnSurf.x(); + suly = posOnSurf.y(); + errx = errX; + ich = m_idHelper->channel(id); + istr = stripNumber; + itype = m_idHelper->channelType(id); + if( type == 0 ){ + ipadeta = m_idHelper->padEta(id); + ipadphi = m_idHelper->padPhi(id); + } + +// const MuonClusterOnTrack* rot = m_muonClusterCreator->createRIO_OnTrack( *prd, hit.globalPosition() ); +// if( rot ){ +// res = rot->localParameters().get(Trk::locX)-hitOnSurface.x(); +// pull = res/rot->localErrorMatrix().error(Trk::locX); +// delete rot; +// } + + m_ntuple->Fill(); + // create SDO + MuonSimData::Deposit deposit(hit.particleLink(), MuonMCData(hitOnSurface.x(),hitOnSurface.y())); + //Record the SDO collection in StoreGate + std::vector<MuonSimData::Deposit> deposits; + deposits.push_back(deposit); + sdoContainer->insert ( std::make_pair ( id, MuonSimData(deposits,0) ) ); + + previousHit = &hit; + + } // end of loop channelType + } // end of loop SimHits + if( msgLvl(MSG::DEBUG) ){ + std::map<Identifier,int>::const_iterator hit = hitsPerChannel.begin(); + std::map<Identifier,int>::const_iterator hit_end = hitsPerChannel.end(); + msg(MSG::DEBUG) << " number of channels with hit " << hitsPerChannel.size() << " nhits " << nhits << std::endl; + for( ;hit!=hit_end;++hit ){ + msg(MSG::DEBUG) << " " << m_idHelperTool->toString(hit->first) << " -> " << hit->second << std::endl; + } + msg(MSG::DEBUG) << endreq; + } + std::string key = "STGC_Measurements"; + ATH_MSG_DEBUG(" Done! Total number of sTgc chambers with PRDS: " << prdContainer->numberOfCollections() << " key " << key); + if (evtStore()->record(prdContainer,key).isFailure()) { + ATH_MSG_ERROR ( "Unable to record sTgcPrepData container in StoreGate" ); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; +} + +StatusCode sTgcFastDigitizer::finalize() { + //m_ntuple_SimHit->Write(); + m_ntuple->Write(); + m_file->Write(); + m_file->Close(); + + return StatusCode::SUCCESS; +} + + +//+++++++++++++++++++++++++++++++++++++++++++++++ +double sTgcFastDigitizer::getResolution(float inAngle_space) const +{ + // 0 degree --> 0.18mm; 10 degree --> + const int NIndex = 2; + //double Reso[NIndex] = {0.18, 0.20, 0.24}; + double Reso[NIndex] = {0.06, 0.30}; + double Angle[NIndex] = {0., 60.}; + + int index = 1; + inAngle_space = fabs(inAngle_space); + while(index<NIndex && inAngle_space>Angle[index]){ + index++; + } + + double Resolution = 0.; + + if(index==NIndex) Resolution = Reso[NIndex-1]; + else Resolution = Reso[index-1] + (inAngle_space - Angle[index-1]) / (Angle[index]-Angle[index-1]) * (Reso[index] - Reso[index-1]); + + ATH_MSG_VERBOSE("sTgcFastDigitizer::getResolution(" << inAngle_space << ") = " <<Resolution ); + + return Resolution; +} + + +//+++++++++++++++++++++++++++++++++++++++++++++++ +uint16_t sTgcFastDigitizer::bcTagging(float digitTime, int channelType) const { + + double offset, window; + if(channelType == 1) { // strip + offset = m_timeWindowOffsetStrip; + window = m_timeWindowStrip; + } + else { // wire gangs or pad + offset = m_timeWindowOffsetWire; + window = m_timeWindowWire; + } + + uint16_t bctag = 0; + if(-m_bunchCrossingTime+offset < digitTime && digitTime < -m_bunchCrossingTime+offset+window) { + bctag = (bctag | 0x1); + } + if( offset < digitTime && digitTime < offset+window) { + bctag = (bctag | 0x2); + } + if(+m_bunchCrossingTime+offset < digitTime && digitTime < +m_bunchCrossingTime+offset+window) { + bctag = (bctag | 0x4); + } + return bctag; +} + + +//+++++++++++++++++++++++++++++++++++++++++++++++ +float sTgcFastDigitizer::timeJitter(float inAngle_time) const +{ + + int ithAngle = static_cast<int>(inAngle_time/5.); + float wAngle = inAngle_time/5. - static_cast<float>(ithAngle); + int jthAngle; + if (ithAngle > 11) { + ithAngle = 12; + jthAngle = 12; + } + else { + jthAngle = ithAngle+1; + } + + float jitter; + float prob = 1.; + float probRef = 0.; + + while (prob > probRef) { + prob = CLHEP::RandFlat::shoot(m_rndmEngine, 0.0, 1.0); + jitter = CLHEP::RandFlat::shoot(m_rndmEngine, 0.0, 1.0)*40.; // trial time jitter in nsec + int ithJitter = static_cast<int>(jitter); + // probability distribution calculated from weighted sum between neighboring bins of angles + probRef = (1.-wAngle)*m_vecAngle_Time[ithAngle][ithJitter] + + wAngle *m_vecAngle_Time[jthAngle][ithJitter]; + } + return jitter; +} + + +//+++++++++++++++++++++++++++++++++++++++++++++++ +bool sTgcFastDigitizer::readFileOfTimeJitter() +{ + + const char* const fileName = "sTGC_Digitization_timejitter.dat"; + std::string fileWithPath = PathResolver::find_file (fileName, "DATAPATH"); + + std::ifstream ifs; + if (fileWithPath != "") { + ifs.open(fileWithPath.c_str(), std::ios::in); + } + else { + ATH_MSG_ERROR("readFileOfTimeJitter(): Could not find file " << fileName); + return false; + } + + if(ifs.bad()){ + ATH_MSG_ERROR("readFileOfTimeJitter(): Could not find file " << fileName); + return false; + } + + int angle = 0; + int bins = 0; + int i = 0; + float prob = 0.; + + while(ifs.good()){ + ifs >> angle >> bins; + if (ifs.eof()) break; + if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << "readFileOfTimeJitter(): Timejitter, angle, Number of bins, prob. dist.: " << angle << " " << bins << " "; + m_vecAngle_Time.resize(i + 1); + for (int j = 0; j < 41/*bins*/; j++) { + ifs >> prob; + m_vecAngle_Time[i].push_back(prob); + if( msgLvl(MSG::VERBOSE) ){ + if( j == 0) msg(MSG::VERBOSE) << "readFileOfTimeJitter(): "; + msg(MSG::VERBOSE) << prob << " "; + } + } + if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << endreq; + i++; + } + ifs.close(); + return true; +} diff --git a/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/sTgcFastDigitizer.h b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/sTgcFastDigitizer.h new file mode 100644 index 0000000000000000000000000000000000000000..9fb4ad2cc2cd931032e528d3a36cc9ea3a7b6048 --- /dev/null +++ b/MuonSpectrometer/MuonDigitization/MuonFastDigitization/src/sTgcFastDigitizer.h @@ -0,0 +1,146 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef MUONDIGITIZATION_sTgcFASTDIGITIZER_H +#define MUONDIGITIZATION_sTgcFASTDIGITIZER_H + +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" +#include "StoreGate/StoreGateSvc.h" + +//Random +#include "CLHEP/Random/RandomEngine.h" +#include "AthenaKernel/IAtRndmGenSvc.h" +#include "CLHEP/Random/RandGauss.h" +#include "MuonIdHelpers/MuonIdHelperTool.h" +#include "MuonRecToolInterfaces/IMuonClusterOnTrackCreator.h" + +class TTree; +class TFile; + +class sTgcIdHelper; +namespace MuonGM { + class MuonDetectorManager; +} + +class IAtRndmGenSvc; +class ActiveStoreSvc; + +class sTgcFastDigitizer : public AthAlgorithm { + + public: + + sTgcFastDigitizer(const std::string& name, ISvcLocator* pSvcLocator); + ~sTgcFastDigitizer(); + + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + ServiceHandle<IAtRndmGenSvc> getRndmSvc() const { return m_rndmSvc; } // Random number service + CLHEP::HepRandomEngine *getRndmEngine() const { return m_rndmEngine; } // Random number engine used + + private: + const MuonGM::MuonDetectorManager* m_detManager; + const sTgcIdHelper* m_idHelper; + + int m_channelTypes; // 1 -> strips, 2 -> strips+wires, 3 -> strips/wires/pads + + TFile* m_file; + //TTree* m_ntuple_SimHit; + TTree* m_ntuple; + float slx; // local position simhit in G4 + float sly; + float slz; + float dlx; // local position simhit in GeoModel frame + float dly; + float dlz; + float sulx; // local position from REin tracking surface frame + float suly; + float tsulx; // local position simhit in tracking surface frame + float tsuly; + float tsulz; + float resx; // residuals in local G4 - GeoModel + float resy; + float resz; + float suresx; // residuals g4 - RE stripPosition in tracking frame + float suresy; + float errx; // error on x and y + float erry; + float res; // residual + pull + float pull; + int is; // simulation Identifier: issmall + int seta; // eta + int sphi; // phi + int sml; // multi layer + int sl; // layer + int ss; // side + int stype; // channel type + int ieta; // offline id fields + int iphi; + int iml; + int il; + int ich; // strip number of Id + int istr; // strip number from RE + int itype; // channel type + int ipadeta; // channel type + int ipadphi; // channel type + int exitcode; // flag reason why prd not made + int mode; // flag digitization mode + int pdg; // pdg ID + int trkid; // track number in G4 + int bct; // bc tag + float tb; // bunchTime + float tj; // time jitter + float tg4; // globalHitTime in G4 + float ttof; // tofCorrection assuming IP; + float gpx; // global position of the simhit + float gpy; + float gpz; + float gpr; // radial position pos.perp() + float gpp; // phi position pos.phi() + float dgpx; // same for readout element center + float dgpy; + float dgpz; + float dgpr; + float dgpp; + float edep; + float e; + float as; + float at; + + + double getResolution(float inAngle_space) const; + uint16_t bcTagging(float digittime, int channelType) const; + float timeJitter(float inAngle_time) const; + + /** + Reads parameters for intrinsic time response from timejitter.dat. + */ + bool readFileOfTimeJitter(); + + + protected: + ToolHandle <Muon::MuonIdHelperTool> m_idHelperTool; // IdHelperTool + ToolHandle <Muon::IMuonClusterOnTrackCreator> m_muonClusterCreator; + ServiceHandle <IAtRndmGenSvc> m_rndmSvc; // Random number service + CLHEP::HepRandomEngine *m_rndmEngine; // Random number engine used - not init in SiDigitization + std::string m_rndmEngineName;// name of random engine + std::string m_inputObjectName; // name of the input objects + double m_timeWindowOffsetWire; + double m_timeWindowOffsetStrip; + double m_timeWindowWire; + double m_timeWindowStrip; + double m_bunchCrossingTime; + double m_energyThreshold; + double m_energyDepositThreshold; + bool m_checkIds; + std::vector<std::vector<float> > m_vecAngle_Time; + +}; + +#endif // MUONDIGITIZATION_sTgcDIGITIZER_H + +