9 #include "art/Framework/Core/ProducesCollector.h"
10 #include "art/Framework/Principal/Event.h"
11 #include "art/Framework/Principal/Handle.h"
12 #include "art/Framework/Services/Registry/ServiceHandle.h"
13 #include "art/Persistency/Common/PtrMaker.h"
14 #include "art/Utilities/ToolMacros.h"
15 #include "art_root_io/TFileDirectory.h"
16 #include "art_root_io/TFileService.h"
17 #include "canvas/Persistency/Common/Assns.h"
18 #include "canvas/Persistency/Common/FindOneP.h"
19 #include "canvas/Persistency/Common/Ptr.h"
20 #include "canvas/Utilities/InputTag.h"
21 #include "cetlib/cpu_timer.h"
22 #include "fhiclcpp/ParameterSet.h"
23 #include "messagefacility/MessageLogger/MessageLogger.h"
51 namespace lar_cluster3d {
64 using HitVector = std::vector<const reco::ClusterHit2D*>;
70 using Hit2DSet = std::set<const reco::ClusterHit2D*, Hit2DSetCompare>;
95 virtual void produces(art::ProducesCollector&)
override;
97 virtual void configure(
const fhicl::ParameterSet&)
override;
154 using HitMatchTriplet = std::tuple<const reco::ClusterHit2D*,const reco::ClusterHit2D*,const reco::ClusterHit3D>;
177 float hitWidthSclFctr = 1.,
178 size_t hitPairCntr = 0)
const;
201 float closestApproach(
const Eigen::Vector3f&,
const Eigen::Vector3f&,
const Eigen::Vector3f&,
const Eigen::Vector3f&,
float&,
float&)
const;
325 m_channelFilter(&art::ServiceHandle<lariov::ChannelStatusService
const>()->GetProvider())
335 collector.produces< std::vector<recob::Hit>>();
336 collector.produces< art::Assns<recob::Wire, recob::Hit>>();
337 collector.produces< art::Assns<raw::RawDigit, recob::Hit>>();
344 m_hitFinderTagVec = pset.get<std::vector<art::InputTag>>(
"HitFinderTagVec", {
"gaushit"});
354 m_invalidTPCVec = pset.get<std::vector<int> >(
"InvalidTPCVec", std::vector<int>());
362 m_geometry = art::ServiceHandle<geo::Geometry const>{}.get();
371 if (m_outputHistograms)
373 art::ServiceHandle<art::TFileService>
tfs;
375 m_tupleTree = tfs->make<TTree>(
"Hit3DBuilderTree",
"Tree by SnippetHit3DBuilderICARUS");
487 return (*left).getAvePeakTime() < (*right).getAvePeakTime();
492 bool operator()(
const reco::HitPairClusterMap::iterator&
left,
const reco::HitPairClusterMap::iterator&
right)
495 if (left->second.size() == right->second.size())
496 return left->first < right->first;
498 return left->second.size() > right->second.size();
513 auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
514 auto const det_prop = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clock_data);
535 std::unique_ptr<std::vector<recob::Hit>> outputHitPtrVec(
new std::vector<recob::Hit>);
548 if (!hitPairList.empty())
554 std::unique_ptr<art::Assns<recob::Wire, recob::Hit>> wireAssns(
new art::Assns<recob::Wire, recob::Hit>);
559 std::unique_ptr<art::Assns<raw::RawDigit, recob::Hit>> rawDigitAssns(
new art::Assns<raw::RawDigit, recob::Hit>);
564 evt.put(std::move(outputHitPtrVec));
565 evt.put(std::move(wireAssns));
566 evt.put(std::move(rawDigitAssns));
585 cet::cpu_timer theClockMakeHits;
597 theClockMakeHits.stop();
602 mf::LogDebug(
"Cluster3D") <<
">>>>> 3D hit building done, found " << numHitPairs <<
" 3D Hits" << std::endl;
616 if (left.first == left.second)
return false;
617 if (right.first == right.second)
return true;
620 return left.first->first.first < right.first->first.first;
646 size_t totalNumHits(0);
647 size_t hitPairCntr(0);
650 size_t nDeadChanHits(0);
661 PlaneToSnippetHitMap::iterator mapItr0 = planeToSnippetHitMap.find(
geo::PlaneID(cryoIdx,tpcIdx,0));
662 PlaneToSnippetHitMap::iterator mapItr1 = planeToSnippetHitMap.find(
geo::PlaneID(cryoIdx,tpcIdx,1));
663 PlaneToSnippetHitMap::iterator mapItr2 = planeToSnippetHitMap.find(
geo::PlaneID(cryoIdx,tpcIdx,2));
665 size_t nPlanesWithHits = (mapItr0 != planeToSnippetHitMap.end() && !mapItr0->second.empty() ? 1 : 0)
666 + (mapItr1 != planeToSnippetHitMap.end() && !mapItr1->second.empty() ? 1 : 0)
667 + (mapItr2 != planeToSnippetHitMap.end() && !mapItr2->second.empty() ? 1 : 0);
669 if (nPlanesWithHits < 2)
continue;
687 mf::LogDebug(
"Cluster3D") <<
"Total number hits: " << totalNumHits << std::endl;
688 mf::LogDebug(
"Cluster3D") <<
"Created a total of " << hitPairList.size() <<
" hit pairs, counted: " << hitPairCntr << std::endl;
689 mf::LogDebug(
"Cluster3D") <<
"-- Triplets: " << nTriplets <<
", dead channel pairs: " << nDeadChanHits << std::endl;
691 return hitPairList.size();
707 auto SetStartIterator = [](SnippetHitMap::iterator startItr, SnippetHitMap::iterator endItr,
float startTime)
709 while(startItr != endItr)
711 if (startItr->first.second < startTime) startItr++;
717 auto SetEndIterator = [](SnippetHitMap::iterator lastItr, SnippetHitMap::iterator endItr,
float endTime)
719 while(lastItr != endItr)
721 if (lastItr->first.first < endTime) lastItr++;
728 size_t nDeadChanHits(0);
729 size_t nOrphanPairs(0);
736 std::sort(snippetHitMapItrVec.begin(),snippetHitMapItrVec.end(),
SetStartTimeOrder());
739 int nPlanesWithHits(0);
741 for(
auto& pair : snippetHitMapItrVec)
742 if (pair.first != pair.second) nPlanesWithHits++;
744 if (nPlanesWithHits < 2)
break;
750 SnippetHitMap::iterator firstSnippetItr = snippetHitMapItrVec.front().first;
753 SnippetHitMap::iterator snippetHitMapItr1Start = SetStartIterator(snippetHitMapItrVec[1].
first, snippetHitMapItrVec[1].
second, firstSnippetItr->first.first);
754 SnippetHitMap::iterator snippetHitMapItr1End = SetEndIterator( snippetHitMapItr1Start, snippetHitMapItrVec[1].second, firstSnippetItr->first.second);
755 SnippetHitMap::iterator snippetHitMapItr2Start = SetStartIterator(snippetHitMapItrVec[2].first, snippetHitMapItrVec[2].second, firstSnippetItr->first.first);
756 SnippetHitMap::iterator snippetHitMapItr2End = SetEndIterator( snippetHitMapItr2Start, snippetHitMapItrVec[2].second, firstSnippetItr->first.second);
759 size_t curHitListSize(hitPairList.size());
763 size_t n12Pairs =
findGoodHitPairs(firstSnippetItr, snippetHitMapItr1Start, snippetHitMapItr1End, pair12Map);
764 size_t n13Pairs =
findGoodHitPairs(firstSnippetItr, snippetHitMapItr2Start, snippetHitMapItr2End, pair13Map);
766 nDeadChanHits += hitPairList.size() - curHitListSize;
767 curHitListSize = hitPairList.size();
769 if (n12Pairs > n13Pairs)
findGoodTriplets(pair12Map, pair13Map, hitPairList);
778 nTriplets += hitPairList.size() - curHitListSize;
780 snippetHitMapItrVec.front().first++;
783 mf::LogDebug(
"Cluster3D") <<
"--> Created " << nTriplets <<
" triplets of which " << nOrphanPairs <<
" are orphans" << std::endl;
785 return hitPairList.size();
789 SnippetHitMap::iterator& startItr,
790 SnippetHitMap::iterator& endItr,
795 HitVector::iterator firstMaxItr = std::max_element(firstSnippetItr->second.begin(),firstSnippetItr->second.end(),[](
const auto&
left,
const auto&
right){
return left->getHit()->PeakAmplitude() <
right->getHit()->PeakAmplitude();});
796 float firstPHCut = firstMaxItr != firstSnippetItr->second.end() ?
m_pulseHeightFrac * (*firstMaxItr)->getHit()->PeakAmplitude() : 4096.;
799 for(
const auto& hit1 : firstSnippetItr->second)
802 if (hit1->getHit()->DegreesOfFreedom() > 1 && hit1->getHit()->PeakAmplitude() < firstPHCut && hit1->getHit()->PeakAmplitude() <
m_PHLowSelection)
continue;
805 SnippetHitMap::iterator secondHitItr = startItr;
808 while(secondHitItr != endItr)
810 HitVector::iterator secondMaxItr = std::max_element(secondHitItr->second.begin(),secondHitItr->second.end(),[](
const auto&
left,
const auto&
right){
return left->getHit()->PeakAmplitude() <
right->getHit()->PeakAmplitude();});
811 float secondPHCut = secondMaxItr != secondHitItr->second.end() ?
m_pulseHeightFrac * (*secondMaxItr)->getHit()->PeakAmplitude() : 0.;
813 for(
const auto& hit2 : secondHitItr->second)
816 if (hit2->getHit()->DegreesOfFreedom() > 1 && hit2->getHit()->PeakAmplitude() < secondPHCut && hit2->getHit()->PeakAmplitude() <
m_PHLowSelection)
continue;
823 std::vector<const recob::Hit*> recobHitVec = {
nullptr,
nullptr,
nullptr};
825 recobHitVec[hit1->WireID().Plane] = hit1->getHit();
826 recobHitVec[hit2->WireID().Plane] = hit2->getHit();
830 hitMatchMap[wireID].emplace_back(hit1,hit2,pair);
845 if (!pair12Map.empty())
848 std::vector<reco::ClusterHit3D> tempDeadChanVec;
852 std::map<const reco::ClusterHit3D*,bool> usedPairMap;
855 for(
const auto& pair13 : pair13Map)
857 for(
const auto& hit2Dhit3DPair : pair13.second) usedPairMap[&std::get<2>(hit2Dhit3DPair)] =
false;
861 for(
const auto& pair12 : pair12Map)
863 if (pair12.second.empty())
continue;
867 for(
const auto& hit2Dhit3DPair12 : pair12.second)
872 usedPairMap[&pair1] =
false;
875 for(
const auto& pair13 : pair13Map)
877 if (pair13.second.empty())
continue;
879 for(
const auto& hit2Dhit3DPair13 : pair13.second)
882 if (std::get<0>(hit2Dhit3DPair12) != std::get<0>(hit2Dhit3DPair13))
continue;
892 triplet.
setID(hitPairList.size());
893 hitPairList.emplace_back(triplet);
894 usedPairMap[&pair1] =
true;
895 usedPairMap[&pair2] =
true;
905 for(
const auto& pairMapPair : usedPairMap)
907 if (pairMapPair.second)
continue;
912 if (
makeDeadChannelPair(deadChanPair, *pair, 4, 0, 0.)) tempDeadChanVec.emplace_back(deadChanPair);
916 if(!tempDeadChanVec.empty())
919 if (tempDeadChanVec.size() > 1)
922 std::sort(tempDeadChanVec.begin(),tempDeadChanVec.end(),[](
const auto&
left,
const auto&
right){
return left.getDeltaPeakTime()/
left.getSigmaPeakTime() <
right.getDeltaPeakTime()/
right.getSigmaPeakTime();});
925 float firstSig = tempDeadChanVec.front().getDeltaPeakTime() / tempDeadChanVec.front().getSigmaPeakTime();
926 float lastSig = tempDeadChanVec.back().getDeltaPeakTime() / tempDeadChanVec.back().getSigmaPeakTime();
927 float sigRange = lastSig - firstSig;
932 float maxSignificance = std::max(0.75 * (firstSig + lastSig),1.0);
934 std::vector<reco::ClusterHit3D>::iterator firstBadElem = std::find_if(tempDeadChanVec.begin(),tempDeadChanVec.end(),[&maxSignificance](
const auto& pair){
return pair.getDeltaPeakTime()/pair.getSigmaPeakTime() > maxSignificance;});
937 if (
std::distance(tempDeadChanVec.begin(),firstBadElem) > 20) firstBadElem = tempDeadChanVec.begin() + 20;
939 else if (firstBadElem == tempDeadChanVec.begin()) firstBadElem++;
941 tempDeadChanVec.resize(
std::distance(tempDeadChanVec.begin(),firstBadElem));
945 for(
auto& pair : tempDeadChanVec)
947 pair.setID(hitPairList.size());
948 hitPairList.emplace_back(pair);
959 int curTripletCount = hitPairList.size();
962 if (!pairMap.empty())
965 for(
const auto& pair : pairMap)
967 if (pair.second.empty())
continue;
971 for(
const auto& hit2Dhit3DPair : pair.second)
993 if (hit1->
WireID().
Plane == 2 || hit2->WireID().Plane == 2)
999 hitPairList.emplace_back(hit3D);
1000 hitPairList.back().setID(hitPairList.size()-1);
1007 return hitPairList.size() - curTripletCount;
1013 float hitWidthSclFctr,
1014 size_t hitPairCntr)
const
1022 float hit1Sigma = hit1->
getHit()->
RMS();
1025 float hit2Sigma = hit2->
getHit()->
RMS();
1036 float hit1Width = hitWidthSclFctr * hit1Sigma;
1037 float hit2Width = hitWidthSclFctr * hit2Sigma;
1040 if (fabs(hit1Peak - hit2Peak) <= (hit1Width + hit2Width))
1043 float hit1SigSq = std::pow(hit1Sigma,2);
1044 float hit2SigSq = std::pow(hit2Sigma,2);
1045 float deltaPeakTime = std::fabs(hit1Peak - hit2Peak);
1046 float sigmaPeakTime = std::sqrt(hit1SigSq + hit2SigSq);
1053 int planeIdx = (plane1 + plane2) - 1;
1055 float deltaTicks = hit2Peak - hit1Peak;
1057 if (plane1 > plane2) deltaTicks = -deltaTicks;
1064 else if (planeIdx == 1)
1088 float oneOverWghts = hit1SigSq * hit2SigSq / (hit1SigSq + hit2SigSq);
1089 float avePeakTime = (hit1Peak / hit1SigSq + hit2Peak / hit2SigSq) * oneOverWghts;
1091 float hitChiSquare = std::pow((hit1Peak - avePeakTime),2) / hit1SigSq
1092 + std::pow((hit2Peak - avePeakTime),2) / hit2SigSq;
1096 float xPosition = (xPositionHit1 / hit1SigSq + xPositionHit2 / hit2SigSq) * hit1SigSq * hit2SigSq / (hit1SigSq + hit2SigSq);
1098 Eigen::Vector3f position(xPosition,
float(widIntersect.
y),
float(widIntersect.
z)-
m_zPosOffset);
1112 hitVector.resize(3, NULL);
1118 unsigned int tpcIdx = hit1->
WireID().
TPC;
1121 std::vector<geo::WireID> wireIDVec = {
geo::WireID(cryostatIdx,tpcIdx,0,0),
1129 std::vector<float> hitDelTSigVec = {0.,0.,0.};
1131 hitDelTSigVec[hit1->
WireID().
Plane] = deltaPeakTime / sigmaPeakTime;
1132 hitDelTSigVec[hit2->
WireID().
Plane] = deltaPeakTime / sigmaPeakTime;
1188 if (hitWireDist < wirePitch)
1204 if (!hit0) hit0 = pairHitVec[2];
1205 else if (!hit1) hit1 = pairHitVec[2];
1217 unsigned int statusBits(0x7);
1218 float avePeakTime(0.);
1219 float weightSum(0.);
1220 float xPosition(0.);
1226 for(
size_t planeIdx = 0; planeIdx < 3; planeIdx++)
1230 wireIDVec[planeIdx] = hit2D->
WireID();
1239 float weight = 1. / (hitRMS * hitRMS);
1241 avePeakTime += peakTime * weight;
1243 weightSum += weight;
1246 avePeakTime /= weightSum;
1247 xPosition /= weightSum;
1252 Eigen::Vector3f position(xPosition,
1253 float((pairYZVec[0] + pair0hYZVec[0] + pair1hYZVec[0]) / 3.),
1254 float((pairYZVec[1] + pair0hYZVec[1] + pair1hYZVec[1]) / 3.));
1257 float hitChiSquare(0.);
1258 float sigmaPeakTime(std::sqrt(1./weightSum));
1259 std::vector<float> hitDelTSigVec;
1261 for(
const auto& hit2D : hitVector)
1263 float hitRMS = hit2D->getHit()->RMS();
1269 float combRMS = std::sqrt(hitRMS*hitRMS - sigmaPeakTime*sigmaPeakTime);
1270 float peakTime = hit2D->getTimeTicks();
1271 float deltaTime = peakTime - avePeakTime;
1272 float hitSig = deltaTime / combRMS;
1274 hitChiSquare += hitSig * hitSig;
1276 hitDelTSigVec.emplace_back(std::fabs(hitSig));
1281 int lowMinIndex(std::numeric_limits<int>::max());
1282 int lowMaxIndex(std::numeric_limits<int>::min());
1283 int hiMinIndex(std::numeric_limits<int>::max());
1284 int hiMaxIndex(std::numeric_limits<int>::min());
1287 for(
const auto& hit2D : hitVector)
1295 int hitStart = hit2D->getHit()->PeakTime() - range - 0.5;
1296 int hitStop = hit2D->getHit()->PeakTime() + range + 0.5;
1298 lowMinIndex = std::min(hitStart, lowMinIndex);
1299 lowMaxIndex = std::max(hitStart, lowMaxIndex);
1300 hiMinIndex = std::min(hitStop + 1, hiMinIndex);
1301 hiMaxIndex = std::max(hitStop + 1, hiMaxIndex);
1305 if (hitChiSquare < m_maxHit3DChiSquare && hiMinIndex > lowMaxIndex)
1308 std::vector<float> chargeVec;
1310 for(
const auto& hit2D : hitVector)
1311 chargeVec.push_back(
chargeIntegral(hit2D->getHit()->PeakTime(),hit2D->getHit()->PeakAmplitude(),hit2D->getHit()->RMS(),1.,lowMaxIndex,hiMinIndex));
1313 float totalCharge = std::accumulate(chargeVec.begin(),chargeVec.end(),0.) / float(chargeVec.size());
1314 float overlapRange = float(hiMinIndex - lowMaxIndex);
1315 float overlapFraction = overlapRange / float(hiMaxIndex - lowMinIndex);
1318 std::vector<float> smallestChargeDiffVec;
1319 std::vector<float> chargeAveVec;
1320 float smallestDiff(std::numeric_limits<float>::max());
1321 float maxDeltaPeak(0.);
1322 size_t chargeIndex(0);
1324 for(
size_t idx = 0; idx < 3; idx++)
1326 size_t leftIdx = (idx + 2) % 3;
1327 size_t rightIdx = (idx + 1) % 3;
1329 smallestChargeDiffVec.push_back(
std::abs(chargeVec[leftIdx] - chargeVec[rightIdx]));
1330 chargeAveVec.push_back(
float(0.5 * (chargeVec[leftIdx] + chargeVec[rightIdx])));
1332 if (smallestChargeDiffVec.back() < smallestDiff)
1334 smallestDiff = smallestChargeDiffVec.back();
1339 float deltaPeakTime = hitVector[rightIdx]->getTimeTicks() - hitVector[leftIdx]->getTimeTicks();
1341 if (
std::abs(deltaPeakTime) > maxDeltaPeak) maxDeltaPeak =
std::abs(deltaPeakTime);
1345 int deltaTimeIdx = (hitVector[leftIdx]->WireID().Plane + hitVector[rightIdx]->WireID().Plane) - 1;
1346 float combRMS = std::sqrt(std::pow(hitVector[leftIdx]->getHit()->RMS(),2) + std::pow(hitVector[rightIdx]->getHit()->RMS(),2));
1351 if (deltaTimeIdx == 0)
1353 m_deltaTime0Vec.emplace_back(
float(hitVector[1]->getTimeTicks() - hitVector[0]->getTimeTicks()));
1356 else if (deltaTimeIdx == 1)
1358 m_deltaTime1Vec.emplace_back(
float(hitVector[2]->getTimeTicks() - hitVector[0]->getTimeTicks()));
1363 m_deltaTime2Vec.emplace_back(
float(hitVector[2]->getTimeTicks() - hitVector[1]->getTimeTicks()));
1369 float chargeAsymmetry = (chargeAveVec[chargeIndex] - chargeVec[chargeIndex]) / (chargeAveVec[chargeIndex] + chargeVec[chargeIndex]);
1372 if (chargeAsymmetry < -1. || chargeAsymmetry > 1.)
1376 std::cout <<
"============> Charge asymmetry out of range: " << chargeAsymmetry <<
" <============" << std::endl;
1377 std::cout <<
" hit C: " << hitWireID.
Cryostat <<
", TPC: " << hitWireID.
TPC <<
", Plane: " << hitWireID.
Plane <<
", Wire: " << hitWireID.
Wire << std::endl;
1378 std::cout <<
" charge: " << chargeVec[0] <<
", " << chargeVec[1] <<
", " << chargeVec[2] << std::endl;
1379 std::cout <<
" index: " << chargeIndex <<
", smallest diff: " << smallestDiff << std::endl;
1384 float deltaPeakTime = *std::max_element(hitDelTSigVec.begin(),hitDelTSigVec.end());
1400 if (maxDeltaPeak > 3. * overlapRange)
return result;
1420 for(
const auto& hit2D : hitVector)
1444 bool success(
false);
1454 double wirePosArr[3] = {0.,0.,0.};
1457 Eigen::Vector3f wirePos0(wirePosArr[0],wirePosArr[1],wirePosArr[2]);
1467 Eigen::Vector3f wirePos1(wirePosArr[0],wirePosArr[1],wirePosArr[2]);
1478 if (
closestApproach(wirePos0, wireDir0, wirePos1, wireDir1, arcLen0, arcLen1))
1483 Eigen::Vector3f poca0 = wirePos0 + arcLen0 * wireDir0;
1485 widIntersection.
y = poca0[1];
1486 widIntersection.
z = poca0[2];
1496 const Eigen::Vector3f& u0,
1497 const Eigen::Vector3f& P1,
1498 const Eigen::Vector3f& u1,
1500 float& arcLen1)
const
1503 Eigen::Vector3f w0 = P0 - P1;
1505 float b(u0.dot(u1));
1507 float d(u0.dot(w0));
1508 float e(u1.dot(w0));
1509 float den(a * c - b * b);
1511 arcLen0 = (b *
e - c * d) / den;
1512 arcLen1 = (a *
e - b * d) / den;
1514 Eigen::Vector3f poca0 = P0 + arcLen0 * u0;
1515 Eigen::Vector3f poca1 = P1 + arcLen1 * u1;
1517 return (poca0 - poca1).norm();
1529 for(
int sigPos = low; sigPos < hi; sigPos++)
1531 float arg = (float(sigPos) - peakMean + 0.5) / peakSigma;
1532 integral += peakAmp *
std::exp(-0.5 * arg * arg);
1540 size_t maxChanStatus,
1541 size_t minChanStatus,
1542 float minOverlap)
const
1550 size_t missPlane(2);
1575 bool wireOneStatus = m_channelStatus[wireID.
Plane][wireID.
Wire+1] < maxChanStatus && m_channelStatus[wireID.
Plane][wireID.
Wire+1] >= minChanStatus;
1578 if(wireStatus || wireOneStatus)
1581 if (!wireStatus) wireID.
Wire += 1;
1594 newPosition[1] = (newPosition[1] + widIntersect0.
y + widIntersect1.
y) / 3.;
1595 newPosition[2] = (newPosition[2] + widIntersect0.
z + widIntersect1.
z - 2. *
m_zPosOffset) / 3.;
1617 static const float minCharge(0.);
1624 for (
const auto& hit2D : hit2DSet)
1626 if (hit2D->getHit()->Integral() < minCharge)
continue;
1628 float hitVPeakTime(hit2D->getTimeTicks());
1629 float deltaPeakTime(pairAvePeakTime-hitVPeakTime);
1631 if (deltaPeakTime > pairDeltaTimeLimits)
continue;
1633 if (deltaPeakTime < -pairDeltaTimeLimits)
break;
1635 pairDeltaTimeLimits = fabs(deltaPeakTime);
1644 static const float minCharge(0.);
1646 int numberInRange(0);
1650 for (
const auto& hit2D : hit2DSet)
1652 if (hit2D->getHit()->Integral() < minCharge)
continue;
1654 float hitVPeakTime(hit2D->getTimeTicks());
1655 float deltaPeakTime(pairAvePeakTime-hitVPeakTime);
1657 if (deltaPeakTime > range)
continue;
1659 if (deltaPeakTime < -range)
break;
1664 return numberInRange;
1677 wireID.
Wire = int(distanceToWire);
1679 catch(std::exception& exc)
1682 mf::LogWarning(
"Cluster3D") <<
"Exception caught finding nearest wire, position - " << exc.what() << std::endl;
1694 float distance = std::numeric_limits<float>::max();
1703 double wirePosArr[3] = {0.,0.,0.};
1706 Eigen::Vector3f wirePos(wirePosArr[0],wirePosArr[1],wirePosArr[2]);
1715 Eigen::Vector3f hitPosition(wirePos[0],position[1],position[2]);
1718 double arcLen = (hitPosition - wirePos).
dot(wireDir);
1723 Eigen::Vector3f docaVec = hitPosition - (wirePos + arcLen * wireDir);
1725 distance = docaVec.norm();
1728 catch(std::exception& exc)
1731 mf::LogWarning(
"Cluster3D") <<
"Exception caught finding nearest wire, position - " << exc.what() << std::endl;
1761 std::vector<const recob::Hit*> recobHitVec;
1766 art::Handle< std::vector<recob::Hit> > recobHitHandle;
1767 evt.getByLabel(inputTag, recobHitHandle);
1769 if (!recobHitHandle.isValid() || recobHitHandle->size() == 0)
continue;
1771 recobHitVec.reserve(recobHitVec.size() + recobHitHandle->size());
1773 for(
const auto&
hit : *recobHitHandle) recobHitVec.push_back(&
hit);
1777 if (recobHitVec.empty())
return;
1779 cet::cpu_timer theClockMakeHits;
1784 auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
1785 auto const det_prop = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clock_data);
1788 std::string debugMessage(
"");
1791 std::map<geo::PlaneID,double> planeIDToPositionMap;
1805 std::ostringstream outputString;
1810 outputString <<
" Det prop plane 0: " << det_prop.GetXTicksOffset(
geo::PlaneID(cryoIdx,tpcIdx,0)) <<
", plane 1: " << det_prop.GetXTicksOffset(
geo::PlaneID(cryoIdx,tpcIdx,1)) <<
", plane 2: " << det_prop.GetXTicksOffset(
geo::PlaneID(cryoIdx,tpcIdx,2)) <<
", Trig: " <<
trigger_offset(clock_data) <<
"\n";
1811 debugMessage += outputString.str() +
"\n";
1814 double xPosition(det_prop.ConvertTicksToX(0., 2, tpcIdx, cryoIdx));
1816 planeIDToPositionMap[
geo::PlaneID(cryoIdx,tpcIdx,2)] = xPosition;
1822 for(
const auto& planeToPositionPair : planeIDToPositionMap)
1824 std::ostringstream outputString;
1826 outputString <<
"***> Plane " << planeToPositionPair.first <<
" has time=0 position: " << planeToPositionPair.second <<
"\n";
1828 debugMessage += outputString.str();
1831 mf::LogDebug(
"Cluster3D") << debugMessage << std::endl;
1838 for (
const auto& recobHit : recobHitVec)
1841 if (recobHit->Integral() < 0.)
continue;
1848 HitStartEndPair hitStartEndPair(recobHit->StartTick(),recobHit->EndTick());
1851 if (hitStartEndPair.second <= hitStartEndPair.first)
1853 std::cout <<
"Yes, found a hit with end time less than start time: " << hitStartEndPair.first <<
"/" << hitStartEndPair.second <<
", mult: " << recobHit->Multiplicity() << std::endl;
1859 for(
auto wireID : wireIDs)
1869 double xPosition(det_prop.ConvertTicksToX(recobHit->PeakTime(), planeID.
Plane, planeID.
TPC, planeID.
Cryostat));
1884 theClockMakeHits.stop();
1896 std::vector<recob::Hit>& hitPtrVec,
1900 cet::cpu_timer theClockBuildNewHits;
1908 std::set<const reco::ClusterHit2D*> visitedHit2DSet;
1911 art::PtrMaker<recob::Hit> ptrMaker(event);
1922 for(
size_t idx = 0; idx < hit3D.getHits().size(); idx++)
1926 if (!hit2D)
continue;
1929 if (visitedHit2DSet.find(hit2D) == visitedHit2DSet.end())
1931 visitedHit2DSet.insert(hit2D);
1940 recobHitToPtrMap[newHit] = ptrMaker(hitPtrVec.size()-1);
1948 size_t numNewHits = hitPtrVec.size();
1952 theClockBuildNewHits.stop();
1957 mf::LogDebug(
"Cluster3D") <<
">>>>> New output recob::Hit size: " << numNewHits <<
" (vs " <<
m_clusterHit2DMasterList.size() <<
" input)" << std::endl;
1965 wireAssns = art::Assns<recob::Wire, recob::Hit>();
1969 std::unordered_map<raw::ChannelID_t, art::Ptr<recob::Wire>> channelToWireMap;
1974 art::ValidHandle<std::vector<recob::Hit>> hitHandle = evt.getValidHandle<std::vector<recob::Hit>>(inputTag);
1976 art::FindOneP<recob::Wire> hitToWireAssns(hitHandle, evt, inputTag);
1978 if (hitToWireAssns.isValid())
1980 for(
size_t wireIdx = 0; wireIdx < hitToWireAssns.size(); wireIdx++)
1982 art::Ptr<recob::Wire> wire = hitToWireAssns.at(wireIdx);
1984 channelToWireMap[wire->Channel()] = wire;
1990 for(
const auto& hitPtrPair : recobHitPtrMap)
1994 std::unordered_map<raw::ChannelID_t, art::Ptr<recob::Wire>>::iterator chanWireItr = channelToWireMap.find(channel);
1996 if (!(chanWireItr != channelToWireMap.end()))
2002 wireAssns.addSingle(chanWireItr->second, hitPtrPair.second);
2011 rawDigitAssns = art::Assns<raw::RawDigit, recob::Hit>();
2015 std::unordered_map<raw::ChannelID_t, art::Ptr<raw::RawDigit>> channelToRawDigitMap;
2020 art::ValidHandle<std::vector<recob::Hit>> hitHandle = evt.getValidHandle<std::vector<recob::Hit>>(inputTag);
2022 art::FindOneP<raw::RawDigit> hitToRawDigitAssns(hitHandle, evt, inputTag);
2024 if (hitToRawDigitAssns.isValid())
2026 for(
size_t rawDigitIdx = 0; rawDigitIdx < hitToRawDigitAssns.size(); rawDigitIdx++)
2028 art::Ptr<raw::RawDigit> rawDigit = hitToRawDigitAssns.at(rawDigitIdx);
2030 channelToRawDigitMap[rawDigit->Channel()] = rawDigit;
2036 for(
const auto& hitPtrPair : recobHitPtrMap)
2040 std::unordered_map<raw::ChannelID_t, art::Ptr<raw::RawDigit>>::iterator chanRawDigitItr = channelToRawDigitMap.find(channel);
2042 if (chanRawDigitItr == channelToRawDigitMap.end())
2048 rawDigitAssns.addSingle(chanRawDigitItr->second, hitPtrPair.second);
void initialize(size_t id, unsigned int statusBits, const Eigen::Vector3f &position, float totalCharge, float avePeakTime, float deltaPeakTime, float sigmaPeakTime, float hitChiSquare, float overlapFraction, float chargeAsymmetry, float docaToAxis, float arclenToPoca, const ClusterHit2DVec &hitVec, const std::vector< float > &hitDelTSigVec, const std::vector< geo::WireID > &wireIDVec)
bool makeHitPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit2D *hit1, const reco::ClusterHit2D *hit2, float hitWidthSclFctr=1., size_t hitPairCntr=0) const
Make a HitPair object by checking two hits.
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
std::map< geo::PlaneID, float > PlaneToT0OffsetMap
bool makeHitTriplet(reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pairIn, const reco::ClusterHit2D *hit2) const
Make a 3D HitPair object by checking two hits.
PlaneToT0OffsetMap m_PlaneToT0OffsetMap
virtual void Hit3DBuilder(art::Event &, reco::HitPairList &, RecobHitToPtrMap &) override
Given a set of recob hits, run DBscan to form 3D clusters.
void setWireID(const geo::WireID &wid) const
float m_LongHitStretchFctr
std::vector< float > m_timeVector
double z
z position of intersection
std::list< reco::ClusterHit3D > HitPairList
SnippetHit3DBuilderICARUS(fhicl::ParameterSet const &pset)
Constructor.
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
void clear()
clear the tuple vectors before processing next event
std::vector< int > m_smallIndexVec
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
std::vector< float > m_deltaPeakTimePlane1Vec
float getTimeTicks() const
void CreateNewRecobHitCollection(art::Event &, reco::HitPairList &, std::vector< recob::Hit > &, RecobHitToPtrMap &)
Create a new 2D hit collection from hits associated to 3D space points.
std::vector< float > m_hitAsymmetryVec
TTree * m_tupleTree
output analysis tree
std::vector< float > m_2hit1stPHVec
std::vector< float > m_overlapRangeVec
std::vector< float > m_chiSquare3DVec
const Eigen::Vector3f getPosition() const
bool SetHitTimeOrder(const reco::ClusterHit2D *left, const reco::ClusterHit2D *right)
std::vector< float > m_2hitSumPHVec
float RMS() const
RMS of the hit shape, in tick units.
What follows are several highly useful typedefs which we want to expose to the outside world...
Declaration of signal hit object.
virtual float getTimeToExecute(IHit3DBuilder::TimeValues index) const override
If monitoring, recover the time to execute a particular function.
void BuildHit3D(reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
std::vector< float > m_maxDeltaPeakVec
std::vector< float > m_overlapFractionVec
void makeWireAssns(const art::Event &, art::Assns< recob::Wire, recob::Hit > &, RecobHitToPtrMap &) const
Create recob::Wire to recob::Hit associations.
The data type to uniquely identify a Plane.
const geo::WireID & WireID() const
bool operator()(const reco::ClusterHit2D *, const reco::ClusterHit2D *) const
size_t BuildHitPairMap(PlaneToSnippetHitMap &planeToHitVectorMap, reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
std::vector< float > m_deltaTime2Vec
void BuildChannelStatusVec(PlaneToWireToHitSetMap &planeToWiretoHitSetMap) const
Create the internal channel status vector (assume will eventually be event-by-event) ...
std::vector< float > m_deltaPeakSigmaPlane2Vec
int DegreesOfFreedom() const
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
virtual void configure(const fhicl::ParameterSet &) override
Interface for configuring the particular algorithm tool.
std::vector< float > m_deltaSigma0Vec
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
const geo::Geometry * m_geometry
WireID_t Wire
Index of the wire within its plane.
float getSigmaPeakTime() const
std::vector< float > m_2hitDeltaPHVec
bool m_weHaveAllBeenHereBefore
std::map< geo::PlaneID, WireToHitSetMap > PlaneToWireToHitSetMap
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
PlaneToSnippetHitMap m_planeToSnippetHitMap
int findGoodHitPairs(SnippetHitMap::iterator &, SnippetHitMap::iterator &, SnippetHitMap::iterator &, HitMatchTripletVecMap &) const
SnippetHit3DBuilderICARUS class definiton.
std::vector< float > m_deltaSigma2Vec
float m_minPHFor2HitPoints
Set a minimum pulse height for 2 hit space point candidates.
std::vector< ChannelStatusVec > ChannelStatusByPlaneVec
unsigned int getStatusBits() const
std::vector< float > m_deltaPeakSigmaPlane1Vec
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
bool SetPeakHitPairIteratorOrder(const reco::HitPairList::iterator &left, const reco::HitPairList::iterator &right)
float closestApproach(const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, float &, float &) const
function to compute the distance of closest approach and the arc length to the points of closest appr...
std::vector< float > m_deltaTime1Vec
standard_dbscan3dalg useful for diagnostics hits not in a line will not be clustered on on only for track like only for track like on on the smaller the less shower like tracks low
ChannelStatusByPlaneVec m_channelStatus
const recob::Hit * getHit() const
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
std::vector< float > m_deltaSigma1Vec
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
std::vector< SnippetHitMapItrPair > PlaneSnippetHitMapItrPairVec
unsigned short Status_t
type representing channel status
std::vector< art::InputTag > m_hitFinderTagVec
std::vector< float > m_pairWireDistVec
const reco::ClusterHit2D * FindBestMatchingHit(const Hit2DSet &hit2DSet, const reco::ClusterHit3D &pair, float pairDeltaTimeLimits) const
A utility routine for finding a 2D hit closest in time to the given pair.
std::map< geo::WireID, HitMatchTripletVec > HitMatchTripletVecMap
float getAvePeakTime() const
void makeRawDigitAssns(const art::Event &, art::Assns< raw::RawDigit, recob::Hit > &, RecobHitToPtrMap &) const
Create raw::RawDigit to recob::Hit associations.
std::map< size_t, HitVector > HitVectorMap
Class managing the creation of a new recob::Hit object.
Helper functions to create a hit.
virtual void produces(art::ProducesCollector &) override
Each algorithm may have different objects it wants "produced" so use this to let the top level produc...
std::vector< float > m_deltaPeakTimePlane2Vec
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
Hit2DList m_clusterHit2DMasterList
std::list< reco::ClusterHit2D > Hit2DList
std::vector< float > m_maxPullVec
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
std::vector< float > m_qualityMetricVec
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::vector< float > m_spacePointChargeVec
std::vector< float > m_deltaPeakSigmaPlane0Vec
bool m_outputHistograms
Take the time to create and fill some histograms for diagnostics.
size_t BuildHitPairMapByTPC(PlaneSnippetHitMapItrPairVec &planeSnippetHitMapItrPairVec, reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
std::vector< size_t > ChannelStatusVec
define data structure for keeping track of channel status
virtual Status_t Status(raw::ChannelID_t channel) const
Returns a status integer with arbitrary meaning.
geo::Length_t DetLength(geo::TPCID const &tpcid) const
Returns the length of the active volume of the specified TPC.
virtual bool IsGood(raw::ChannelID_t channel) const
Returns whether the specified channel is physical and good.
const lariov::ChannelStatusProvider * m_channelFilter
bool m_useT0Offsets
If true then we will use the LArSoft interplane offsets.
float m_wirePitchScaleFactor
Scaling factor to determine max distance allowed between candidate pairs.
bool WireIDsIntersect(const geo::WireID &, const geo::WireID &, geo::WireIDIntersection &) const
function to detemine if two wires "intersect" (in the 2D sense)
float getXPosition() const
TimeValues
enumerate the possible values for time checking if monitoring timing
Class providing information about the quality of channels.
void CollectArtHits(const art::Event &evt) const
Extract the ART hits and the ART hit-particle relationships.
The geometry of one entire detector, as served by art.
PlaneID_t Plane
Index of the plane within its TPC.
float DistanceFromPointToHitWire(const Eigen::Vector3f &position, const geo::WireID &wireID) const
Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range...
IHit3DBuilder interface class definiton.
This provides an art tool interface definition for tools which construct 3D hits used in 3D clusterin...
std::vector< const reco::ClusterHit2D * > ClusterHit2DVec
std::set< const reco::ClusterHit2D *, Hit2DSetCompare > Hit2DSet
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::map< geo::TPCID, PlaneToWireToHitSetMap > TPCToPlaneToWireToHitSetMap
std::vector< const reco::ClusterHit2D * > HitVector
double HalfL() const
Returns half the length of the wire [cm].
std::vector< HitMatchTriplet > HitMatchTripletVec
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
std::vector< float > m_maxSideVecVec
bool operator()(const reco::HitPairClusterMap::iterator &left, const reco::HitPairClusterMap::iterator &right)
float PeakTime() const
Time of the signal peak, in tick units.
bool operator()(const SnippetHitMapItrPair &left, const SnippetHitMapItrPair &right) const
void setID(const size_t &id) const
std::vector< float > m_deltaTimeVec
std::map< geo::PlaneID, SnippetHitMap > PlaneToSnippetHitMap
Hit has been made into Space Point.
double y
y position of intersection
std::map< geo::TPCID, PlaneToSnippetHitMap > TPCToPlaneToSnippetHitMap
std::vector< float > m_2hit2ndPHVec
float m_maxHit3DChiSquare
Provide ability to select hits based on "chi square".
geo::WireID NearestWireID(const Eigen::Vector3f &position, const geo::WireID &wireID) const
Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range...
void findGoodTriplets(HitMatchTripletVecMap &, HitMatchTripletVecMap &, reco::HitPairList &, bool=false) const
This algorithm takes lists of hit pairs and finds good triplets.
Interface for experiment-specific channel quality info provider.
std::pair< SnippetHitMap::iterator, SnippetHitMap::iterator > SnippetHitMapItrPair
int trigger_offset(DetectorClocksData const &data)
constexpr WireID()=default
Default constructor: an invalid TPC ID.
std::pair< raw::TDCtick_t, raw::TDCtick_t > HitStartEndPair
std::vector< float > m_deltaPeakTimePlane0Vec
2D representation of charge deposited in the TDC/wire plane
art::ServiceHandle< art::TFileService > tfs
float getHitChiSquare() const
PlaneToWireToHitSetMap m_planeToWireToHitSetMap
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
float chargeIntegral(float, float, float, float, int, int) const
Perform charge integration between limits.
double WireCoordinate(Point const &point) const
Returns the coordinate of the point on the plane, in wire units.
bool makeDeadChannelPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pair, size_t maxStatus=4, size_t minStatus=0, float minOverlap=0.2) const
Make a 3D HitPair object from a valid pair and a dead channel in the missing plane.
std::map< HitStartEndPair, HitVector > SnippetHitMap
unsigned int ChannelID_t
Type representing the ID of a readout channel.
TPCID_t TPC
Index of the TPC within its cryostat.
Interface for experiment-specific service for channel quality info.
process_name physics producers generator hPHist_pi physics producers generator P0
std::tuple< const reco::ClusterHit2D *, const reco::ClusterHit2D *, const reco::ClusterHit3D > HitMatchTriplet
This builds a list of candidate hit pairs from lists of hits on two planes.
const ClusterHit2DVec & getHits() const
std::unordered_map< const recob::Hit *, art::Ptr< recob::Hit >> RecobHitToPtrMap
Defines a structure mapping art representation to internal.
std::vector< float > m_smallChargeDiffVec
bool m_saveMythicalPoints
Should we save valid 2 hit space points?
void setPosition(const Eigen::Vector3f &pos) const
std::vector< std::vector< std::vector< float >>> TickCorrectionArray
Data members to follow.
bool SetPairStartTimeOrder(const reco::ClusterHit3D &left, const reco::ClusterHit3D &right)
int FindNumberInRange(const Hit2DSet &hit2DSet, const reco::ClusterHit3D &pair, float range) const
A utility routine for returning the number of 2D hits from the list in a given range.
std::vector< int > m_invalidTPCVec
art framework interface to geometry description
BEGIN_PROLOG could also be cout
float m_maxMythicalChiSquare
Selection cut on mythical points.
std::map< unsigned int, Hit2DSet > WireToHitSetMap
std::vector< float > m_deltaTime0Vec
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
int saveOrphanPairs(HitMatchTripletVecMap &, reco::HitPairList &) const
This will look at storing pair "orphans" where the 2D hits are otherwise unused.
unsigned getStatusBits() const
void setStatusBit(unsigned bits) const
void setStatusBit(unsigned bits) const