2 #include "cetlib/search_path.h"
3 #include "messagefacility/MessageLogger/MessageLogger.h"
27 #include "TMVA/Reader.h"
31 using namespace detail;
39 cet::search_path sp(
"FW_SEARCH_PATH");
41 std::string fullFileSpec;
42 sp.find_file(fMVAShowerParentWeights, fullFileSpec);
43 if (fullFileSpec ==
"") {
69 if (ss3.
ID == 0)
return false;
72 mf::LogVerbatim myprt(
"TC");
73 myprt <<
"Inside FSS: 3S" << ss3.
ID <<
" ->";
74 for (
auto cid : ss3.
CotIDs)
75 myprt <<
" 2S" << cid;
76 myprt <<
" Vx 3V" << ss3.
Vx3ID;
81 unsigned short useParentCID = 0;
82 float maxParentSep = 0;
83 unsigned short usePtSepCID = 0;
88 for (
auto cid : ss3.
CotIDs) {
89 auto& ss = slc.
cots[cid - 1];
91 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
94 if (chgCtrTP.Delta < 0.5)
continue;
95 auto& startTP = stj.Pts[0];
96 float sep =
PosSep(startTP.Pos, chgCtrTP.Pos);
97 if (ss.ParentID > 0) {
98 if (sep > maxParentSep) {
103 else if (sep > maxPtSep) {
107 float costh =
DotProd(chgCtrTP.Dir, startTP.Dir);
108 if (costh < 0) dirOK =
false;
111 if (useParentCID == 0 && usePtSepCID == 0)
return false;
113 unsigned short useCID = useParentCID;
115 useCID = usePtSepCID;
120 auto& ss = slc.
cots[useCID - 1];
121 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
126 ss3.
Start[0] = vx3.X;
127 ss3.
Start[1] = vx3.Y;
128 ss3.
Start[2] = vx3.Z;
132 auto& startTP = stj.Pts[0];
137 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
141 auto& endTP = stj.Pts[2];
143 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
146 auto& startTP = stj.Pts[0];
147 sep =
PosSep(startTP.Pos, endTP.Pos);
148 ss3.
OpenAngle = (endTP.DeltaRMS - startTP.DeltaRMS) / sep;
165 bool noShowers =
true;
166 for (
auto& ss3 : slc.
showers) {
167 if (ss3.ID == 0)
continue;
170 if (noShowers)
return;
177 for (
auto& ss3 : slc.
showers) {
178 if (ss3.ID == 0)
continue;
179 if (ss3.PFPIndex != USHRT_MAX)
continue;
181 showerPFP.TjIDs.resize(ss3.CotIDs.size());
182 for (
unsigned short ii = 0; ii < ss3.CotIDs.size(); ++ii) {
183 unsigned short cid = ss3.CotIDs[ii];
184 if (cid == 0 || cid > slc.
cots.size())
return;
185 auto& ss = slc.
cots[cid - 1];
186 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
187 showerPFP.TjIDs[ii] = stj.ID;
189 showerPFP.PDGCode = 1111;
190 auto& sf = showerPFP.SectionFits[0];
193 sf.DirErr = ss3.DirErr;
194 showerPFP.Vx3ID[0] = ss3.Vx3ID;
197 for (
auto cid : ss3.CotIDs) {
198 auto& ss = slc.
cots[cid - 1];
200 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
201 showerPFP.dEdx[0][plane] = stj.dEdx[0];
202 showerPFP.dEdxErr[0][plane] = 0.3 * stj.dEdx[0];
204 ss3.PFPIndex = slc.
pfps.size();
205 if (ss3.ParentID > 0) {
207 auto& dtrPFP = slc.
pfps[ss3.ParentID - 1];
208 if (dtrPFP.ParentUID > 0) {
211 auto& parPFP =
slices[slcIndx.first].pfps[slcIndx.second];
212 showerPFP.ParentUID = parPFP.UID;
213 std::replace(parPFP.DtrUIDs.begin(), parPFP.DtrUIDs.end(), dtrPFP.UID, showerPFP.UID);
214 dtrPFP.ParentUID = 0;
217 slc.
pfps.push_back(showerPFP);
225 for (
auto& ss3 : slc.
showers) {
226 if (ss3.ID == 0)
continue;
227 for (
unsigned short ii = 0; ii < ss3.CotIDs.size(); ++ii) {
228 unsigned short cid = ss3.CotIDs[ii];
229 auto& ss = slc.
cots[cid - 1];
230 for (
auto tjid : ss.TjIDs) {
233 ss3.Hits.insert(ss3.Hits.end(), tjHits.begin(), tjHits.end());
235 for (
unsigned short end = 0;
end < 2; ++
end) {
238 if (vx2.Vx3ID <= 0) {
245 auto& vx3 = slc.
vtx3s[vx2.Vx3ID - 1];
246 if (vx3.Neutrino)
continue;
254 if (!slc.
pfps.empty()) {
255 for (
auto& pfp : slc.
pfps) {
256 if (pfp.ID == 0)
continue;
257 if (pfp.TjIDs.empty())
continue;
258 unsigned short ndead = 0;
259 for (
auto tjid : pfp.TjIDs) {
260 auto& tj = slc.
tjs[tjid - 1];
261 if (tj.AlgMod[
kKilled]) ++ndead;
263 if (ndead == 0)
continue;
269 for (
auto& vx2 : slc.
vtxs) {
270 if (vx2.ID == 0)
continue;
271 auto vxtjs =
GetAssns(slc,
"2V", vx2.
ID,
"T");
272 if (vxtjs.empty()) vx2.ID = 0;
276 for (
auto& vx3 : slc.
vtx3s) {
277 if (vx3.ID == 0)
continue;
278 auto vxtjs =
GetAssns(slc,
"3V", vx3.
ID,
"T");
295 if (!reconstruct)
return false;
300 std::string fcnLabel =
"FS";
304 for (
unsigned short plane = 0; plane < TPC.
Nplanes(); ++plane) {
306 for (
auto& ss : slc.
cots)
307 if (ss.CTP == inCTP)
return false;
316 std::vector<std::vector<std::vector<int>>> bigList(slc.
nPlanes);
317 for (
unsigned short plane = 0; plane < TPC.
Nplanes(); ++plane) {
318 std::vector<std::vector<int>> tjList;
322 if (tjList.empty())
continue;
323 bigList[plane] = tjList;
325 unsigned short nPlanesWithShowers = 0;
326 for (
unsigned short plane = 0; plane < TPC.
Nplanes(); ++plane)
327 if (!bigList.empty()) ++nPlanesWithShowers;
328 if (nPlanesWithShowers < 2)
return false;
329 for (
unsigned short plane = 0; plane < TPC.
Nplanes(); ++plane) {
332 bool prtCTP = (prt2S && inCTP ==
debug.
CTP);
334 for (
auto& tjl : bigList[plane]) {
335 if (tjl.empty())
continue;
337 mf::LogVerbatim myprt(
"TC");
338 myprt <<
"Plane " << plane <<
" tjList";
339 for (
auto& tjID : tjl)
340 myprt <<
" " << tjID;
343 if (ss.ID == 0)
continue;
352 if (inCTP == UINT_MAX)
continue;
353 if (slc.
cots.empty())
continue;
369 bool tryMerge =
false;
370 for (
unsigned short ii = 0; ii < slc.
cots.size(); ++ii) {
371 auto& ss = slc.
cots[ii];
372 if (ss.ID == 0)
continue;
373 if (ss.CTP != inCTP)
continue;
381 if (slc.
cots.empty())
return false;
389 for (
auto& ss3 : slc.
showers) {
390 if (ss3.ID == 0)
continue;
391 FindParent(detProp, fcnLabel, slc, ss3, prt3S);
399 for (
auto& ss3 : slc.
showers) {
400 if (ss3.ID == 0)
continue;
406 for (
auto& ss : slc.
cots) {
407 if (ss.ID == 0)
continue;
408 if (ss.SS3ID > 0)
continue;
409 bool killMe = (ss.TjIDs.size() == 1 || ss.Energy <
tcc.
showerTag[3]);
415 unsigned short nNewShowers = 0;
416 for (
auto& ss : slc.
cots) {
417 if (ss.ID == 0)
continue;
418 if (ss.TjIDs.empty())
continue;
423 return (nNewShowers > 0);
433 std::string fcnLabel = inFcnLabel +
".R3D2";
439 for (
unsigned short ii = 0; ii < slc.
showers.size() - 1; ++ii) {
441 if (iss3.ID == 0)
continue;
442 auto iPInSS3 =
GetAssns(slc,
"3S", iss3.
ID,
"P");
444 mf::LogVerbatim myprt(
"TC");
445 myprt << fcnLabel <<
" 3S" << iss3.ID <<
" ->";
446 for (
auto pid : iPInSS3)
447 myprt <<
" P" << pid;
449 for (
unsigned short jj = ii + 1; jj < slc.
showers.size(); ++jj) {
451 if (jss3.ID == 0)
continue;
452 auto jPInSS3 =
GetAssns(slc,
"3S", jss3.
ID,
"P");
454 if (shared.empty())
continue;
456 mf::LogVerbatim myprt(
"TC");
457 myprt << fcnLabel <<
" Conflict i3S" << iss3.ID <<
" and j3S" << jss3.ID <<
" share";
458 for (
auto pid : shared)
459 myprt <<
" P" << pid;
462 for (
auto pid : shared) {
463 auto& pfp = slc.
pfps[pid - 1];
467 mf::LogVerbatim(
"TC")
468 << fcnLabel <<
" i3S" << iss3.ID <<
" prob " << std::setprecision(3) << iProb
469 <<
" j3S" << jss3.ID <<
" prob " << jProb;
472 RemovePFP(fcnLabel, slc, pfp, jss3,
true, prt);
474 AddPFP(fcnLabel, slc, pfp.
ID, iss3,
true, prt);
477 RemovePFP(fcnLabel, slc, pfp, iss3,
true, prt);
478 AddPFP(fcnLabel, slc, pfp.
ID, jss3,
true, prt);
487 if (parentSearchDone) {
488 for (
auto& ss3 : slc.
showers) {
489 if (ss3.ID == 0)
continue;
490 auto PIn3S =
GetAssns(slc,
"3S", ss3.
ID,
"P");
491 for (
auto pid : PIn3S) {
492 if (pid == ss3.ParentID)
continue;
493 auto& pfp = slc.
pfps[pid - 1];
494 for (
unsigned short end = 0;
end < 2; ++
end) {
495 if (pfp.Vx3ID[
end] <= 0)
continue;
497 mf::LogVerbatim myprt(
"TC");
498 myprt << fcnLabel <<
" Detach 3S" << ss3.ID <<
" -> P" << pfp.ID <<
"_" <<
end
499 <<
" -> 3V" << pfp.Vx3ID[
end];
500 if (pfp.ParentUID > 0) myprt <<
" ->Parent P" << pfp.ParentUID;
504 if (pfp.ParentUID > 0) {
506 auto& parentPFP =
slices[slcIndx.first].pfps[slcIndx.second];
507 std::vector<int> newDtrUIDs;
508 for (
auto did : parentPFP.DtrUIDs)
509 if (did != pfp.UID) newDtrUIDs.push_back(did);
510 parentPFP.DtrUIDs = newDtrUIDs;
519 for (
auto& ss : slc.
cots) {
520 if (ss.ID == 0)
continue;
521 if (ss.SS3ID > 0)
continue;
522 std::vector<int> matchedTjs;
523 for (
auto tid : ss.TjIDs)
524 if (slc.
tjs[tid - 1].AlgMod[
kMat3D]) matchedTjs.push_back(tid);
525 if (matchedTjs.empty())
continue;
529 bool isCompatible =
true;
530 for (
auto tid : matchedTjs) {
531 auto TInP =
GetAssns(slc,
"T", tid,
"P");
532 if (TInP.empty())
continue;
535 auto PIn3S =
GetAssns(slc,
"P", TInP[0],
"3S");
536 for (
auto sid : PIn3S) {
538 auto& ss3 = slc.
showers[sid - 1];
540 if (mergeWith3S == 0) mergeWith3S = sid;
541 if (mergeWith3S > 0 && mergeWith3S != sid) isCompatible =
false;
545 mf::LogVerbatim myprt(
"TC");
546 myprt << fcnLabel <<
" 2S" << ss.ID <<
" is not 3D-matched but has 3D-matched Tjs:";
547 for (
auto tid : matchedTjs) {
548 myprt <<
" T" << tid;
549 auto TInP =
GetAssns(slc,
"T", tid,
"P");
550 if (!TInP.empty()) { myprt <<
"->P" << TInP[0]; }
553 if (mergeWith3S == 0 && ss.Energy < 50) {
557 else if (mergeWith3S > 0 && isCompatible) {
558 auto& ss3 = slc.
showers[mergeWith3S - 1];
559 for (
auto cid : ss3.CotIDs) {
560 auto& oss = slc.
cots[cid - 1];
561 if (oss.CTP != ss.CTP)
continue;
562 if (!
UpdateShower(fcnLabel, slc, ss3, prt))
return false;
580 if (ss3.
ID == 0)
return false;
582 if (ss3.
CotIDs.size() < 3)
return true;
583 std::string fcnLabel = inFcnLabel +
".R3D";
589 std::vector<ShowerStruct> oldSS(ss3.
CotIDs.size());
590 for (
unsigned short ii = 0; ii < ss3.
CotIDs.size(); ++ii) {
594 std::vector<std::vector<int>> plist(ss3.
CotIDs.size());
595 for (
unsigned short ci = 0; ci < ss3.
CotIDs.size(); ++ci) {
597 for (
auto tid : ss.TjIDs) {
598 auto tToP =
GetAssns(slc,
"T", tid,
"P");
599 if (tToP.empty())
continue;
602 if (std::find(plist[ci].
begin(), plist[ci].
end(), pid) == plist[ci].end())
603 plist[ci].push_back(pid);
607 std::vector<std::array<int, 2>> p_cnt;
608 for (
auto& pl : plist) {
609 for (
auto pid : pl) {
610 unsigned short indx = 0;
611 for (indx = 0; indx < p_cnt.size(); ++indx)
612 if (p_cnt[indx][0] == pid)
break;
613 if (indx == p_cnt.size()) {
615 p_cnt.push_back(std::array<int, 2>{{pid, 1}});
623 mf::LogVerbatim myprt(
"TC");
624 myprt << fcnLabel <<
" 3S" << ss3.
ID <<
"\n";
625 for (
unsigned short ci = 0; ci < ss3.
CotIDs.size(); ++ci) {
626 myprt <<
" -> 2S" << ss3.
CotIDs[ci] <<
" ->";
627 for (
auto pid : plist[ci])
628 myprt <<
" P" << pid;
631 myprt <<
" P<ID>_count:";
632 for (
auto& pc : p_cnt)
633 myprt <<
" P" << pc[0] <<
"_" << pc[1];
636 for (
auto& pc : p_cnt) {
638 if (pc[1] == (
int)ss3.
CotIDs.size())
continue;
641 auto& pfp = slc.
pfps[pc[0] - 1];
642 if (pfp.TjIDs.size() > 2) {
644 auto PIn2S =
GetAssns(slc,
"P", pfp.
ID,
"2S");
646 if (!sDiff.empty() &&
650 mf::LogVerbatim myprt(
"TC");
651 myprt << fcnLabel <<
" 3S" << ss3.
ID <<
" P" << pfp.ID <<
" ->";
652 for (
auto sid : PIn2S)
653 myprt <<
" 2S" << sid;
655 for (
auto sid : sDiff)
656 myprt <<
" 2S" << sid;
659 if (
AddPFP(fcnLabel, slc, pfp.
ID, ss3,
true, prt)) {
662 if (ss3.
CotIDs.size() != oldSS.size())
return false;
663 for (
unsigned short ii = 0; ii < ss3.
CotIDs.size(); ++ii)
669 for (
unsigned short ii = 0; ii < oldSS.size(); ++ii) {
670 auto& ss = oldSS[ii];
671 slc.
cots[ss.ID - 1] = ss;
678 auto& pfp = slc.
pfps[pc[0] - 1];
679 unsigned short nearEnd = 1 -
FarEnd(slc, pfp, ss3.
ChgPos);
684 mf::LogVerbatim myprt(
"TC");
685 myprt << fcnLabel <<
" one occurrence: P" << pfp.ID <<
"_" << nearEnd
686 <<
" closest to ChgPos";
687 myprt <<
" ChgPos " << std::fixed << std::setprecision(1) << ss3.
ChgPos[0] <<
" "
689 myprt <<
" sep " << sep;
690 myprt <<
" InShowerProb " << prob;
692 if (sep < 30 && prob > 0.3 &&
AddPFP(fcnLabel, slc, pfp.
ID, ss3,
true, prt)) {
693 if (prt) mf::LogVerbatim(
"TC") <<
" AddPFP success";
695 else if (!
RemovePFP(fcnLabel, slc, pfp, ss3,
true, prt)) {
696 if (prt) mf::LogVerbatim(
"TC") <<
" RemovePFP failed";
701 if (!
UpdateShower(fcnLabel, slc, ss3, prt))
return false;
714 if (ss.
ID == 0)
return;
716 std::string fcnLabel = inFcnLabel +
".KVIS";
718 for (
auto& vx2 : slc.
vtxs) {
719 if (vx2.ID == 0)
continue;
720 if (vx2.CTP != ss.
CTP)
continue;
722 if (vx2.Vx3ID > 0 && slc.
vtx3s[vx2.Vx3ID - 1].Neutrino)
continue;
725 mf::LogVerbatim(
"TC") << fcnLabel <<
" Clobber 2V" << vx2.ID <<
" -> 3V" << vx2.Vx3ID
726 <<
" inside 2S" << ss.
ID;
729 if (dc.TjIDs[0] == 0)
continue;
730 if (dc.Vx2ID != vx2.ID)
continue;
732 mf::LogVerbatim(
"TC") << fcnLabel <<
" Remove T" << dc.TjIDs[0] <<
"-T" << dc.TjIDs[0]
733 <<
" in dontCluster";
738 auto TIn3V =
GetAssns(slc,
"3V", vx2.Vx3ID,
"T");
739 for (
auto tid : TIn3V)
741 auto& vx3 = slc.
vtx3s[vx2.Vx3ID - 1];
745 auto TIn2V =
GetAssns(slc,
"2V", vx2.
ID,
"T");
746 for (
auto tid : TIn2V)
761 if (slc.
nPlanes != 3)
return false;
762 if (ss3.
CotIDs.size() != 2)
return false;
766 std::string fcnLabel = inFcnLabel +
".CIS";
767 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID;
772 std::vector<int> iplist;
773 for (
auto tid : iss.TjIDs) {
774 auto plist =
GetAssns(slc,
"T", tid,
"P");
775 if (!plist.empty()) iplist.insert(iplist.end(), plist.begin(), plist.end());
777 std::vector<int> jplist;
778 for (
auto tid : jss.TjIDs) {
779 auto plist =
GetAssns(slc,
"T", tid,
"P");
780 if (!plist.empty()) jplist.insert(jplist.end(), plist.begin(), plist.end());
784 if (shared.empty())
return false;
786 std::vector<int> flat = iss.TjIDs;
787 flat.insert(flat.end(), jss.TjIDs.begin(), jss.TjIDs.end());
790 std::vector<int> ktlist;
791 for (
auto pid : shared) {
792 auto& pfp = slc.
pfps[pid - 1];
793 for (
auto tid : pfp.TjIDs) {
795 if (std::find(flat.begin(), flat.end(), tid) != flat.end())
continue;
796 if (std::find(ktlist.begin(), ktlist.end(), tid) == ktlist.end()) ktlist.push_back(tid);
798 auto& tj = slc.
tjs[tid - 1];
799 for (
unsigned short end = 0;
end < 2; ++
end) {
800 if (tj.VtxID[
end] <= 0)
continue;
801 auto& vx2 = slc.
vtxs[tj.VtxID[
end] - 1];
802 auto TIn2V =
GetAssns(slc,
"2V", vx2.
ID,
"T");
803 for (
auto vtid : TIn2V) {
804 if (std::find(ktlist.begin(), ktlist.end(), vtid) == ktlist.end())
805 ktlist.push_back(vtid);
810 if (ktlist.empty())
return false;
812 std::vector<int> ksslist;
813 for (
auto tid : ktlist) {
814 auto& tj = slc.
tjs[tid - 1];
815 if (tj.SSID == 0)
continue;
817 auto& ss = slc.
cots[tj.SSID - 1];
820 mf::LogVerbatim(
"TC") << fcnLabel <<
" Found existing T" << tid <<
" -> 2S" << ss.ID
821 <<
" -> 3S" << ss.SS3ID <<
" assn. Give up";
824 if (std::find(ksslist.begin(), ksslist.end(), ss.ID) == ksslist.end())
825 ksslist.push_back(ss.ID);
830 mf::LogVerbatim myprt(
"TC");
831 myprt << fcnLabel <<
" 3S" << ss3.
ID <<
"\n";
832 myprt <<
" -> i2S" << iss.ID <<
" ->";
833 for (
auto pid : iplist)
834 myprt <<
" P" << pid;
836 myprt <<
" -> j2S" << jss.ID <<
" ->";
837 for (
auto pid : jplist)
838 myprt <<
" P" << pid;
842 unsigned short kplane = 3 - iPlaneID.
Plane - jPlaneID.
Plane;
843 myprt <<
" kplane " << kplane <<
" ktlist:";
844 for (
auto tid : ktlist)
845 myprt <<
" T" << tid;
846 myprt <<
" ktlistEnergy " << ktlistEnergy;
847 if (ksslist.empty()) { myprt <<
"\n No matching showers in kplane"; }
850 myprt <<
" Candidate showers:";
851 for (
auto ssid : ksslist) {
852 myprt <<
" 2S" << ssid;
853 auto& sst = slc.
cots[ssid - 1];
854 if (sst.SS3ID > 0) myprt <<
"_3S" << sst.SS3ID;
858 if (ksslist.size() > 1) {
860 mf::LogVerbatim(
"TC") << fcnLabel
861 <<
" Found more than 1 shower. Need some better code here";
866 mf::LogVerbatim(
"TC") << fcnLabel
867 <<
" ktlistEnergy exceeds 2 * ss3 energy. Need some better code here";
871 if (ksslist.empty()) {
874 if (kss.ID == 0)
return false;
877 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" create new 2S" << kss.ID
880 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" UpdateShower failed 2S" << kss.ID;
885 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" StoreShower failed";
889 ss3.
CotIDs.push_back(kss.ID);
890 auto& stj = slc.
tjs[kss.ShowerTjID - 1];
897 auto& ss = slc.
cots[ksslist[0] - 1];
899 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" found pfp-matched 2S" << ss.ID;
901 ss3.
CotIDs.push_back(ss.ID);
902 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
922 if (ss.
ID == 0)
return false;
923 if (ss.
TjIDs.empty())
return false;
927 if (stj.Pts.size() != 3)
return false;
929 std::string fcnLabel = inFcnLabel +
".U2S";
941 for (
auto& stp : stj.Pts) {
943 stp.Pos = {{0.0, 0.0}};
945 stp.HitPos = {{0.0, 0.0}};
947 stp.Dir = {{0.0, 0.0}};
957 for (
auto tjid : ss.
TjIDs) {
958 if (tjid <= 0 || tjid > (
int)slc.
tjs.size())
return false;
959 auto& tj = slc.
tjs[tjid - 1];
960 if (tj.CTP != ss.
CTP)
return false;
962 for (
unsigned short ipt = tj.EndPt[0]; ipt <= tj.EndPt[1]; ++ipt) {
964 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
965 if (!tp.
UseHit[ii])
continue;
966 unsigned int iht = tp.
Hits[ii];
968 if (
hit.Integral() <= 0)
continue;
972 shpt.
Chg =
hit.Integral();
973 shpt.
Pos[0] =
hit.WireID().Wire;
975 ss.
ShPts.push_back(shpt);
979 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << ss.
ID <<
" nShPts " << ss.
ShPts.size();
981 if (ss.
ShPts.size() < 3)
return false;
984 auto& stp1 = stj.Pts[1];
985 for (
auto& shpt : ss.
ShPts) {
986 stp1.Pos[0] += shpt.Chg * shpt.Pos[0];
987 stp1.Pos[1] += shpt.Chg * shpt.Pos[1];
988 stj.TotChg += shpt.Chg;
990 if (stj.TotChg <= 0)
return false;
991 stp1.Pos[0] /= stj.TotChg;
992 stp1.Pos[1] /= stj.TotChg;
995 mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << ss.
ID <<
" Chg ctr " <<
PrintPos(slc, stp1.Pos)
996 <<
" Energy " << (int)ss.
Energy <<
" MeV";
1003 unsigned short pend =
FarEnd(slc, ptj, stp1.Pos);
1004 auto& ptp = ptj.Pts[ptj.EndPt[pend]];
1006 stp1.Ang = atan2(stp1.Dir[1], stp1.Dir[0]);
1016 for (
auto& shpt : ss.
ShPts) {
1018 double xx = shpt.Pos[0] - stp1.Pos[0];
1019 double yy = shpt.Pos[1] - stp1.Pos[1];
1020 sumx += shpt.Chg * xx;
1021 sumy += shpt.Chg * yy;
1022 sumxy += shpt.Chg * xx * yy;
1023 sumx2 += shpt.Chg * xx * xx;
1024 sumy2 += shpt.Chg * yy * yy;
1026 double delta = sum * sumx2 - sumx * sumx;
1027 if (delta == 0)
return false;
1031 double B = (sumxy * sum - sumx * sumy) / delta;
1033 stp1.Dir[0] = cos(stp1.Ang);
1034 stp1.Dir[1] = sin(stp1.Ang);
1038 ss.
Angle = stp1.Ang;
1040 mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << ss.
ID <<
" dir " << std::fixed
1041 << std::setprecision(2) << stp1.Dir[0] <<
" " << stp1.Dir[1]
1042 <<
" Angle " << stp1.Ang;
1043 for (
unsigned short ipt = 0; ipt < 3; ++ipt) {
1044 if (ipt == 1)
continue;
1045 stj.Pts[ipt].Dir = stp1.Dir;
1046 stj.Pts[ipt].Ang = stp1.Ang;
1050 std::vector<SortEntry> sortVec(ss.
ShPts.size());
1051 unsigned short indx = 0;
1052 double cs = cos(-stp1.Ang);
1053 double sn = sin(-stp1.Ang);
1054 for (
auto& shpt : ss.
ShPts) {
1055 double xx = shpt.Pos[0] - stp1.Pos[0];
1056 double yy = shpt.Pos[1] - stp1.Pos[1];
1057 shpt.RotPos[0] = cs * xx - sn * yy;
1058 shpt.RotPos[1] = sn * xx + cs * yy;
1059 sortVec[indx].index = indx;
1060 sortVec[indx].val = shpt.RotPos[0];
1065 auto tPts = ss.
ShPts;
1066 for (
unsigned short ii = 0; ii < ss.
ShPts.size(); ++ii)
1067 ss.
ShPts[ii] = tPts[sortVec[ii].index];
1071 for (
auto& shpt : ss.ShPts) {
1072 alongTrans[0] += shpt.Chg *
std::abs(shpt.RotPos[0]);
1073 alongTrans[1] += shpt.Chg *
std::abs(shpt.RotPos[1]);
1075 alongTrans[0] /= stj.TotChg;
1076 alongTrans[1] /= stj.TotChg;
1077 if (alongTrans[1] == 0)
return false;
1078 ss.AspectRatio = alongTrans[1] / alongTrans[0];
1080 mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << ss.ID <<
" AspectRatio " << ss.AspectRatio;
1086 if (ss.ParentID > 0) {
1089 auto& ptj = slc.tjs[ss.ParentID - 1];
1091 unsigned short pend =
FarEnd(slc, ptj, stp1.Pos);
1092 auto& ptp = ptj.Pts[ptj.EndPt[pend]];
1093 auto& firstShPt = ss.ShPts[0];
1094 auto& lastShPt = ss.ShPts[ss.ShPts.size() - 1];
1095 if (
PosSep2(ptp.Pos, lastShPt.Pos) <
PosSep2(ptp.Pos, firstShPt.Pos))
1097 stj.Pts[0].Pos = ptp.Pos;
1101 if (stj.Pts[2].DeltaRMS < stj.Pts[0].DeltaRMS)
ReverseShower(fcnLabel, slc, ss, prt);
1102 stj.Pts[0].Pos = ss.ShPts[0].Pos;
1105 if (stj.Pts[2].DeltaRMS > 0) ss.DirectionFOM = stj.Pts[0].DeltaRMS / stj.Pts[2].DeltaRMS;
1107 stj.Pts[2].Pos = ss.ShPts[ss.ShPts.size() - 1].Pos;
1110 ss.NeedsUpdate =
false;
1111 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << ss.ID <<
" updated";
1123 if (ss3.
ID == 0)
return false;
1124 if (ss3.
CotIDs.size() < 2)
return false;
1126 std::string fcnLabel = inFcnLabel +
".U3S";
1129 for (
auto cid : ss3.
CotIDs) {
1130 auto& ss = slc.
cots[cid - 1];
1131 if (ss.NeedsUpdate && prt)
1132 std::cout << fcnLabel <<
" ********* 3S" << ss3.
ID <<
" 2S" << ss.ID
1133 <<
" needs an update...\n";
1141 if (pfp.Vx3ID[pend] != ss3.
Vx3ID) {
1144 <<
" with a vertex that is not attached the shower\n";
1149 std::array<Point3_t, 3> pos;
1152 std::array<double, 3> chg;
1153 for (
unsigned short ipt = 0; ipt < 3; ++ipt) {
1155 for (
unsigned short xyz = 0; xyz < 3; ++xyz) {
1160 unsigned short nok = 0;
1161 for (
unsigned short ipt = 0; ipt < 3; ++ipt) {
1162 if (chg[ipt] == 0)
continue;
1163 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
1164 pos[ipt][xyz] /= chg[ipt];
1169 if (nok != 3)
return false;
1189 for (
auto cid : ss3.
CotIDs) {
1190 auto& ss = slc.
cots[cid - 1];
1191 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
1193 ss3.
Energy[plane] = ss.Energy;
1199 ss3.
dEdx[plane] = stj.dEdx[0];
1200 ss3.
dEdxErr[plane] = 0.3 * stj.dEdx[0];
1204 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" updated";
1212 std::string inFcnLabel,
1219 for (
unsigned short ii = 0; ii < ss3.
CotIDs.size() - 1; ++ii) {
1220 unsigned short icid = ss3.
CotIDs[ii];
1221 for (
unsigned short jj = ii + 1; jj < ss3.
CotIDs.size(); ++jj) {
1222 unsigned short jcid = ss3.
CotIDs[jj];
1223 fom +=
Match3DFOM(detProp, inFcnLabel, slc, icid, jcid, prt);
1227 if (cnt == 0)
return 100;
1234 std::string inFcnLabel,
1241 if (icid == 0 || icid > (
int)slc.
cots.size())
return 100;
1242 if (jcid == 0 || jcid > (
int)slc.
cots.size())
return 100;
1243 if (kcid == 0 || kcid > (
int)slc.
cots.size())
return 100;
1245 float ijfom =
Match3DFOM(detProp, inFcnLabel, slc, icid, jcid, prt);
1246 float jkfom =
Match3DFOM(detProp, inFcnLabel, slc, jcid, kcid, prt);
1248 return 0.5 * (ijfom + jkfom);
1255 std::string inFcnLabel,
1262 if (icid == 0 || icid > (
int)slc.
cots.size())
return 100;
1263 if (jcid == 0 || jcid > (
int)slc.
cots.size())
return 100;
1265 auto& iss = slc.
cots[icid - 1];
1266 auto& istj = slc.
tjs[iss.ShowerTjID - 1];
1267 auto& jss = slc.
cots[jcid - 1];
1268 auto& jstj = slc.
tjs[jss.ShowerTjID - 1];
1270 if (iss.CTP == jss.CTP)
return 100;
1272 std::string fcnLabel = inFcnLabel +
".MFOM";
1274 float energyAsym =
std::abs(iss.Energy - jss.Energy) / (iss.Energy + jss.Energy);
1277 if ((iss.Energy > 200 || jss.Energy > 200) && energyAsym > 0.5)
return 50;
1285 float pos1fom =
std::abs(ix - jx) / 10;
1287 float mfom = energyAsym * pos1fom;
1290 mf::LogVerbatim myprt(
"TC");
1291 myprt << fcnLabel <<
" i2S" << iss.ID <<
" j2S" << jss.ID;
1292 myprt << std::fixed << std::setprecision(2);
1293 myprt <<
" pos1fom " << pos1fom;
1294 myprt <<
" energyAsym " << energyAsym;
1295 myprt <<
" mfom " << mfom;
1307 if (tjList.size() < 2)
return;
1309 bool didMerge =
true;
1312 for (
unsigned short itl = 0; itl < tjList.size() - 1; ++itl) {
1313 if (tjList[itl].
empty())
continue;
1314 for (
unsigned short jtl = itl + 1; jtl < tjList.size(); ++jtl) {
1315 if (tjList[itl].
empty())
continue;
1316 auto& itList = tjList[itl];
1317 auto& jtList = tjList[jtl];
1319 bool jtjInItjList =
false;
1320 for (
auto& jtj : jtList) {
1321 if (std::find(itList.begin(), itList.end(), jtj) != itList.end()) {
1322 jtjInItjList =
true;
1325 if (jtjInItjList)
break;
1329 itList.insert(itList.end(), jtList.begin(), jtList.end());
1339 unsigned short imEmpty = 0;
1340 while (imEmpty < tjList.size()) {
1341 for (imEmpty = 0; imEmpty < tjList.size(); ++imEmpty)
1342 if (tjList[imEmpty].
empty())
break;
1343 if (imEmpty < tjList.size()) tjList.erase(tjList.begin() + imEmpty);
1347 for (
auto& tjl : tjList) {
1348 std::sort(tjl.begin(), tjl.end());
1349 auto last = std::unique(tjl.begin(), tjl.end());
1350 tjl.erase(last, tjl.end());
1367 if (pfp.
ID == 0 || ss3.
ID == 0)
return false;
1369 std::string fcnLabel = inFcnLabel +
".RemP";
1370 for (
auto tid : pfp.
TjIDs) {
1371 for (
auto cid : ss3.
CotIDs) {
1372 auto& ss = slc.
cots[cid - 1];
1373 if (std::find(ss.TjIDs.begin(), ss.TjIDs.end(), tid) == ss.TjIDs.end())
continue;
1374 if (!
RemoveTj(fcnLabel, slc, tid, ss, doUpdate, prt))
return false;
1397 std::string fcnLabel = inFcnLabel +
".AddP";
1399 if (pID <= 0 || pID > (
int)slc.
pfps.size())
return false;
1400 auto& pfp = slc.
pfps[pID - 1];
1402 if (pfp.TPCID != ss3.
TPCID) {
1403 mf::LogVerbatim(
"TC") << fcnLabel <<
" P" << pID <<
" is in the wrong TPC for 3S" << ss3.
ID;
1407 for (
auto tid : pfp.TjIDs) {
1408 auto& tj = slc.
tjs[tid - 1];
1411 auto& ss = slc.
cots[tj.SSID - 1];
1412 if (ss.SS3ID > 0 && ss.SS3ID != ss3.
ID) {
1414 mf::LogVerbatim(
"TC") << fcnLabel <<
" Conflict: 3S" << ss3.
ID <<
" adding P" << pfp.ID
1415 <<
" -> T" << tid <<
" is in 2S" << tj.SSID <<
" that is in 3S"
1416 << ss.SS3ID <<
" that is not this shower";
1421 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" adding P" << pfp.ID <<
" -> T"
1422 << tid <<
" is in the correct shower 2S" << tj.SSID;
1426 mf::LogVerbatim myprt(
"TC");
1427 myprt << fcnLabel <<
" 3S" << ss3.
ID <<
" adding P" << pfp.ID <<
" -> T" << tid;
1428 myprt <<
" tj.SSID 2S" << tj.SSID;
1431 for (
auto& cid : ss3.
CotIDs) {
1432 auto& ss = slc.
cots[cid - 1];
1433 if (ss.CTP != tj.CTP)
continue;
1435 AddTj(fcnLabel, slc, tid, ss, doUpdate, prt);
1452 if (tjID <= 0 || tjID > (
int)slc.
tjs.size())
return false;
1454 std::string fcnLabel = inFcnLabel +
".AddT";
1459 mf::LogVerbatim(
"TC") << fcnLabel <<
" T" << tjID <<
" is in the wrong CTP for 2S" << ss.
ID;
1465 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" T" << tjID <<
" is already in 2S" << ss.
ID;
1470 mf::LogVerbatim(
"TC") << fcnLabel <<
" Can't add T" << tjID <<
" to 2S" << ss.
ID
1471 <<
". it is already used in 2S" << tj.
SSID;
1476 ss.
TjIDs.push_back(tjID);
1480 for (
unsigned short ii = 0; ii < ss.
NearTjIDs.size(); ++ii) {
1484 unsigned short cnt = 0;
1485 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
1487 if (tp.
Chg == 0)
continue;
1488 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii)
1489 if (tp.
UseHit[ii]) ++cnt;
1491 unsigned short newSize = ss.
ShPts.size() + cnt;
1492 cnt = ss.
ShPts.size();
1493 ss.
ShPts.resize(newSize);
1495 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
1497 if (tp.
Chg == 0)
continue;
1498 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1500 unsigned int iht = tp.
Hits[ii];
1501 ss.
ShPts[cnt].HitIndex = iht;
1504 ss.
ShPts[cnt].Chg =
hit.Integral();
1505 ss.
ShPts[cnt].Pos[0] =
hit.WireID().Wire;
1511 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Added T" << tj.
ID <<
" to 2S" << ss.
ID;
1514 if (doUpdate)
return UpdateShower(fcnLabel, slc, ss, prt);
1530 if (TjID > (
int)slc.
tjs.size())
return false;
1532 std::string fcnLabel = inFcnLabel +
".RTj";
1539 mf::LogVerbatim(
"TC") << fcnLabel <<
" Can't Remove T" << TjID <<
" from 2S" << ss.
ID
1540 <<
" because it's not in this shower";
1547 for (
unsigned short ii = 0; ii < ss.
TjIDs.size(); ++ii) {
1548 if (TjID == ss.
TjIDs[ii]) {
1554 if (!gotit)
return false;
1559 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Remove T" << TjID <<
" from 2S" << ss.
ID;
1561 if (ss.
TjIDs.empty()) {
1562 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Removed the last Tj. Killing 2S" << ss.
ID;
1578 std::string inFcnLabel,
1591 if (ss3.
ID == 0)
return false;
1592 if (ss3.
CotIDs.size() < 2)
return false;
1598 std::string fcnLabel = inFcnLabel +
".FPar";
1604 double shMaxAlong, along95;
1607 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" Estimated energy " << (int)energy
1608 <<
" MeV shMaxAlong " << shMaxAlong <<
" along95 " << along95
1609 <<
" truPFP " << truPFP;
1630 std::array<int, 2> parID{{0, 0}};
1631 std::array<float, 2> parFOM{{-1E6, -1E6}};
1634 std::vector<bool> isParent(slc.
pfps.size() + 1,
false);
1635 for (
auto& oldSS3 : slc.
showers) {
1636 if (oldSS3.ID == 0)
continue;
1637 isParent[oldSS3.ParentID] =
true;
1641 auto TjsInSS3 =
GetAssns(slc,
"3S", ss3.
ID,
"T");
1642 if (TjsInSS3.empty())
return false;
1644 for (
auto& pfp : slc.
pfps) {
1645 if (pfp.ID == 0)
continue;
1646 bool dprt = (pfp.ID == truPFP);
1647 if (pfp.TPCID != ss3.
TPCID)
continue;
1649 if (pfp.PDGCode == 14 || pfp.PDGCode == 14)
continue;
1651 if (pfp.PDGCode == 1111)
continue;
1653 if (isParent[pfp.ID])
continue;
1655 if (
DontCluster(slc, pfp.TjIDs, TjsInSS3))
continue;
1657 float pfpEnergy = 0;
1658 float minEnergy = 1E6;
1659 for (
auto tid : pfp.TjIDs) {
1660 auto& tj = slc.
tjs[tid - 1];
1661 float energy =
ChgToMeV(tj.TotChg);
1662 pfpEnergy += energy;
1663 if (energy < minEnergy) minEnergy = energy;
1665 pfpEnergy -= minEnergy;
1666 pfpEnergy /= (float)(pfp.TjIDs.size() - 1);
1668 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" P" << pfp.ID <<
" E "
1670 if (pfpEnergy > energy)
continue;
1676 if (costh1 < 0.4)
continue;
1684 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" P" << pfp.ID <<
"_" << pEnd
1685 <<
" distToStart " << sqrt(distToStart2) <<
" distToChgPos "
1686 << sqrt(distToChgPos2) <<
" distToEnd " << sqrt(distToEnd2);
1688 unsigned short shEnd = 0;
1689 if (distToEnd2 < distToStart2) shEnd = 1;
1691 if (shEnd == 0 && distToChgPos2 < distToStart2)
continue;
1692 if (shEnd == 1 && distToChgPos2 < distToEnd2)
continue;
1694 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
"_" << shEnd <<
" P" << pfp.ID
1695 <<
"_" << pEnd <<
" costh1 " << costh1;
1701 mf::LogVerbatim(
"TC") << fcnLabel <<
" alongTrans " << alongTrans[0] <<
" "
1706 float distToShowerMax = shMaxAlong -
std::abs(alongTrans[0]);
1708 if (dprt) mf::LogVerbatim(
"TC") << fcnLabel <<
" prob " << prob;
1709 if (prob < 0.1)
continue;
1714 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
1717 for (
auto cid : ss3.
CotIDs) {
1718 auto& ss = slc.
cots[cid - 1];
1719 if (ss.CTP != inCTP)
continue;
1723 if (ssid == 0)
continue;
1724 auto tpFrom =
MakeBareTP(detProp, slc, pos, pToS, inCTP);
1725 auto& ss = slc.
cots[ssid - 1];
1726 auto& stp1 = slc.
tjs[ss.ShowerTjID - 1].Pts[1];
1727 float sep =
PosSep(tpFrom.Pos, stp1.Pos);
1728 float toPos = tpFrom.Pos[0] + 0.5 * tpFrom.Dir[0] * sep;
1732 chgFrac += sep * cf;
1734 if (totSep > 0) chgFrac /= totSep;
1750 mf::LogVerbatim myprt(
"TC");
1752 myprt <<
" 3S" << ss3.
ID <<
"_" << shEnd;
1753 myprt <<
" P" << pfp.ID <<
"_" << pEnd <<
" ParentVars";
1755 myprt <<
" " << std::fixed << std::setprecision(2) << var;
1756 myprt <<
" candParFOM " << candParFOM;
1758 if (candParFOM > parFOM[shEnd]) {
1759 parFOM[shEnd] = candParFOM;
1760 parID[shEnd] = pfp.ID;
1764 if (parID[0] == 0 && parID[1] == 0)
return true;
1769 float aveDirFOM = 0;
1771 for (
auto cid : ss3.
CotIDs)
1772 aveDirFOM += slc.
cots[cid - 1].DirectionFOM;
1773 aveDirFOM /= (float)ss3.
CotIDs.size();
1775 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" parID[0] " << parID[0] <<
" fom "
1776 << parFOM[0] <<
" parID[1] " << parID[1] <<
" fom " << parFOM[1]
1777 <<
" aveDirFOM " << aveDirFOM;
1779 if (parID[0] > 0 && parID[1] > 0 && aveDirFOM > 0.3) {
1784 if (parFOM[1] > parFOM[0]) {
1789 else if (parID[0] > 0) {
1797 if (bestPFP == 0)
return true;
1800 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" setting P" << bestPFP
1801 <<
" as the parent " << fom3D;
1805 std::vector<ShowerStruct> oldSS(ss3.
CotIDs.size());
1806 for (
unsigned short ii = 0; ii < ss3.
CotIDs.size(); ++ii) {
1811 auto& pfp = slc.
pfps[bestPFP - 1];
1813 ss3.
Vx3ID = pfp.Vx3ID[pend];
1816 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" successful update";
1820 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" Failed. Recovering...";
1822 for (
unsigned short ii = 0; ii < oldSS.size(); ++ii) {
1823 auto& ss = oldSS[ii];
1824 slc.
cots[ss.ID - 1] = ss;
1833 std::string inFcnLabel,
1840 if (pfp.
ID == 0 || ss3.
ID == 0)
return false;
1841 if (ss3.
CotIDs.empty())
return false;
1843 std::string fcnLabel = inFcnLabel +
".SP";
1845 for (
auto cid : ss3.
CotIDs) {
1846 auto& ss = slc.
cots[cid - 1];
1847 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
1849 if (ss.ParentID > 0) {
1850 auto& oldParent = slc.
tjs[ss.ParentID - 1];
1856 for (
auto tjid : pfp.
TjIDs) {
1857 auto& tj = slc.
tjs[tjid - 1];
1858 if (tj.CTP != ss.CTP)
continue;
1859 if (std::find(ss.TjIDs.begin(), ss.TjIDs.end(), tjid) == ss.TjIDs.end()) {
1861 if (!
AddTj(fcnLabel, slc, tjid, ss,
false, prt))
return false;
1867 unsigned short npts = tj.EndPt[1] - tj.EndPt[0] + 1;
1868 if (tp.Delta > 0.5 || npts > 20) {
1870 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" parent P" << pfp.
ID <<
" -> T"
1871 << tjid <<
" -> 2S" << ss.ID <<
" parent";
1875 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" parent P" << pfp.
ID <<
" -> T"
1876 << tjid <<
" low projection in plane " << tp.Delta
1877 <<
". Not a parent";
1881 ss.NeedsUpdate =
true;
1883 if (ss3.
Vx3ID > 0) {
1885 auto v2list =
GetAssns(slc,
"3V", vx3.
ID,
"2V");
1886 for (
unsigned short end = 0;
end < 2; ++
end) {
1887 if (tj.VtxID[
end] <= 0)
continue;
1888 if (std::find(v2list.begin(), v2list.end(), tj.VtxID[
end]) != v2list.end())
1889 stj.VtxID[0] = tj.VtxID[
end];
1893 if (!
UpdateShower(fcnLabel, slc, ss, prt))
return false;
1900 float fom3D =
ParentFOM(fcnLabel, slc, pfp, pEnd, ss3, prt);
1901 for (
auto cid : ss3.
CotIDs)
1902 slc.
cots[cid - 1].ParentFOM = fom3D;
1912 if (TjIDs.empty())
return false;
1913 unsigned short cnt = 0;
1914 for (
auto tid : TjIDs) {
1915 if (tid <= 0 || tid > (
int)slc.
tjs.size())
continue;
1929 if (showerEnergy < 10) {
1934 shMaxAlong = 16 * log(showerEnergy / 15);
1936 double scale = 2.75 - 9.29E-4 * showerEnergy;
1937 if (scale < 2) scale = 2;
1938 along95 = scale * shMaxAlong;
1946 double shMaxAlong, shE95Along;
1948 if (shMaxAlong <= 0)
return 0;
1949 double tau = (along + shMaxAlong) / shMaxAlong;
1951 double rms = -0.4 + 2.5 * tau;
1952 if (rms < 0.5) rms = 0.5;
1963 if (showerEnergy < 10)
return 0;
1965 double shMaxAlong, shE95Along;
1972 double tau = (along + shMaxAlong) / shMaxAlong;
1973 if (tau < -1 || tau > 4)
return 0;
1975 double tauHalf, width;
1987 double prob = 1 / (1 +
exp((tau - tauHalf) / width));
1999 if (showerEnergy < 10)
return 0;
2002 double prob =
exp(-0.5 * trans / rms);
2020 if (ss3.
ID == 0 || pfp.
ID == 0)
return 0;
2023 for (
auto cid : ss3.
CotIDs) {
2024 auto& ss = slc.
cots[cid - 1];
2025 if (ss.ID == 0)
continue;
2026 for (
auto tid : pfp.
TjIDs) {
2027 auto& tj = slc.
tjs[tid - 1];
2028 if (tj.CTP != ss.CTP)
continue;
2033 if (cnt == 0)
return 0;
2044 if (ss.
ID == 0 || tj.
ID == 0)
return 0;
2045 if (ss.
CTP != tj.
CTP)
return 0;
2048 if (stj.Pts.size() != 3)
return 0;
2049 unsigned short closePt1, closePt2;
2052 if (doca == 1E6)
return 0;
2053 float showerLen =
PosSep(stj.Pts[0].Pos, stj.Pts[2].Pos);
2055 if (doca > 5 * showerLen)
return 0.01;
2056 auto& stp = stj.Pts[closePt1];
2057 if (stp.DeltaRMS == 0)
return 0;
2058 auto& ttp = tj.
Pts[closePt2];
2061 float rms = stp.DeltaRMS;
2062 if (rms < 1) rms = 1;
2063 float arg = alongTrans[1] / rms;
2064 float radProb =
exp(-0.5 * arg * arg);
2067 arg = alongTrans[0] / rms;
2068 float longProb =
exp(-0.5 * arg * arg);
2070 float prob = radProb * longProb * costh;
2080 unsigned short pend,
2085 if (ss3.
ID == 0)
return 1000;
2088 std::string fcnLabel = inFcnLabel +
".P3FOM";
2090 for (
auto cid : ss3.
CotIDs) {
2091 auto& ss = slc.
cots[cid - 1];
2092 if (ss.ID == 0)
continue;
2095 for (
auto tid : pfp.
TjIDs) {
2096 auto& tj = slc.
tjs[tid - 1];
2097 if (tj.ID == 0)
continue;
2098 if (tj.CTP == ss.CTP) tjid = tid;
2100 if (tjid == 0)
continue;
2101 auto& ptj = slc.
tjs[tjid - 1];
2102 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
2104 unsigned short ptjEnd =
FarEnd(slc, ptj, stj.Pts[1].Pos);
2105 auto& farTP = ptj.Pts[ptj.EndPt[ptjEnd]];
2106 float chgCtrSep2 =
PosSep2(farTP.Pos, stj.Pts[1].Pos);
2107 if (chgCtrSep2 <
PosSep2(farTP.Pos, stj.Pts[0].Pos) &&
2108 chgCtrSep2 <
PosSep2(farTP.Pos, stj.Pts[2].Pos))
2110 float fom =
ParentFOM(fcnLabel, slc, ptj, ptjEnd, ss, dum1, dum2, prt);
2112 if (fom > 50)
continue;
2115 if (ss.AspectRatio > 0) wt = 1 / ss.AspectRatio;
2119 if (wsum == 0)
return 100;
2120 float fom = sum / wsum;
2122 mf::LogVerbatim(
"TC") << fcnLabel <<
" 3S" << ss3.
ID <<
" P" << pfp.
ID <<
" fom "
2123 << std::fixed << std::setprecision(3) << fom;
2132 unsigned short& tjEnd,
2144 if (tjEnd > 1)
return 1000;
2145 if (ss.
Energy == 0)
return 1000;
2147 if (ss.
ID == 0)
return 1000;
2148 if (ss.
TjIDs.empty())
return 1000;
2151 std::string fcnLabel = inFcnLabel +
".PFOM";
2155 mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << ss.
ID <<
" poor AspectRatio "
2179 double shMaxAlong, shE95Along;
2185 if (prob < 0.05)
return 100;
2188 if (alongTrans[1] > shMaxAlong)
return 100;
2190 float longFOM =
std::abs(alongcm + shMaxAlong) / 14;
2194 float transFOM = -1;
2196 transFOM = alongTrans[1] / stp0.
DeltaRMS;
2206 float dang1FOM = dang1 / 0.1;
2210 float dang2FOM = dang1 / 0.1;
2214 std::vector<int> tjlist(1);
2221 if (tj.
VtxID[tjEnd] > 0) {
2224 vx2Score = vx2.
Score;
2226 vxFOM =
std::abs(shMaxAlong - vx2Sep) / 20;
2231 float chgFracFOM = (1 - chgFrac) / 0.1;
2236 float chgFrcBtwFOM = (1 - chgFrac) / 0.05;
2237 fom += chgFrcBtwFOM;
2246 mf::LogVerbatim myprt(
"TC");
2248 myprt <<
" 2S" << ss.
ID;
2249 myprt <<
" T" << tj.
ID <<
"_" << tjEnd <<
" Pos " <<
PrintPos(slc, ptp);
2250 myprt << std::fixed << std::setprecision(2);
2251 myprt <<
" along " << std::fixed << std::setprecision(1) << alongTrans[0] <<
" fom "
2253 myprt <<
" trans " << alongTrans[1] <<
" fom " << transFOM;
2254 myprt <<
" prob " << prob;
2255 myprt <<
" dang1 " << dang1 <<
" fom " << dang1FOM;
2256 myprt <<
" dang2 " << dang2 <<
" fom " << dang2FOM;
2257 myprt <<
" vx2Score " << vx2Score <<
" fom " << vxFOM;
2258 myprt <<
" chgFrac " << chgFrac <<
" fom " << chgFracFOM;
2259 myprt <<
" chgFracBtw " << chgFracBtw <<
" fom " << chgFrcBtwFOM;
2260 myprt <<
" FOM " << fom;
2271 unsigned short tjEnd,
2290 if (tjEnd > 1)
return false;
2292 std::string fcnLabel = inFcnLabel +
".WSTj";
2295 unsigned short otherEnd = 1 - tjEnd;
2297 if (tj.
VtxID[otherEnd] == 0)
return false;
2298 unsigned short ivx = tj.
VtxID[otherEnd] - 1;
2300 if (slc.
vtxs[ivx].Topo != 8 && slc.
vtxs[ivx].Topo != 10)
return false;
2302 mf::LogVerbatim(
"TC") << fcnLabel <<
" Primary candidate " << tj.
ID
2303 <<
" was split by a 3D vertex";
2313 if (slc.
cots.empty())
return;
2315 std::string fcnLabel = inFcnLabel +
".MNS";
2318 mf::LogVerbatim myprt(
"TC");
2319 myprt << fcnLabel <<
" list";
2320 for (
auto& ss : slc.
cots) {
2321 if (ss.CTP != inCTP)
continue;
2322 if (ss.ID == 0)
continue;
2323 myprt <<
" ss.ID " << ss.ID <<
" NearTjs";
2324 for (
auto&
id : ss.NearTjIDs)
2330 bool keepMerging =
true;
2331 while (keepMerging) {
2332 keepMerging =
false;
2333 for (
unsigned short ci1 = 0; ci1 < slc.
cots.size() - 1; ++ci1) {
2335 if (ss1.
CTP != inCTP)
continue;
2336 if (ss1.
ID == 0)
continue;
2337 if (ss1.
TjIDs.empty())
continue;
2339 std::vector<int> ss1list = ss1.
TjIDs;
2341 for (
unsigned short ci2 = ci1 + 1; ci2 < slc.
cots.size(); ++ci2) {
2343 if (ss2.
CTP != inCTP)
continue;
2344 if (ss2.
ID == 0)
continue;
2345 if (ss2.
TjIDs.empty())
continue;
2347 std::vector<int> ss2list = ss2.
TjIDs;
2350 if (shared.empty())
continue;
2352 mf::LogVerbatim myprt(
"TC");
2353 myprt << fcnLabel <<
" Merge 2S" << ss2.
ID <<
" into 2S" << ss1.
ID
2354 <<
"? shared nearby:";
2355 for (
auto tjid : shared)
2356 myprt <<
" T" << tjid;
2359 bool doMerge =
false;
2360 for (
auto& tjID : shared) {
2361 bool inSS1 = (std::find(ss1.
TjIDs.begin(), ss1.
TjIDs.end(), tjID) != ss1.
TjIDs.end());
2362 bool inSS2 = (std::find(ss2.
TjIDs.begin(), ss2.
TjIDs.end(), tjID) != ss2.
TjIDs.end());
2363 if (inSS1 && !inSS2) doMerge =
true;
2364 if (!inSS1 && inSS2) doMerge =
true;
2366 if (inSS1 || inSS2)
continue;
2367 auto& tj = slc.
tjs[tjID - 1];
2369 if (tj.PDGCode == 13 && tj.Pts.size() > 100 && tj.ChgRMS < 0.5) {
2371 mf::LogVerbatim(
"TC")
2372 << fcnLabel <<
" T" << tj.ID <<
" looks like a muon. Don't add it";
2378 if (!TInP.empty()) {
2379 auto& pfp = slc.
pfps[TInP[0] - 1];
2380 if (pfp.PDGCode == 13 &&
MCSMom(slc, pfp.TjIDs) > 500)
continue;
2383 if (
AddTj(fcnLabel, slc, tjID, ss1,
false, prt)) doMerge =
true;
2385 if (!doMerge)
continue;
2389 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" success";
2424 if (slc.
cots.empty())
return;
2426 std::string fcnLabel = inFcnLabel +
".MO";
2430 mf::LogVerbatim(
"TC") << fcnLabel <<
" checking using separation cut " <<
tcc.
showerTag[2];
2435 bool didMerge =
true;
2439 for (
unsigned short ict = 0; ict < slc.
cots.size() - 1; ++ict) {
2440 auto& iss = slc.
cots[ict];
2441 if (iss.ID == 0)
continue;
2442 if (iss.TjIDs.empty())
continue;
2443 if (iss.CTP != inCTP)
continue;
2444 for (
unsigned short jct = ict + 1; jct < slc.
cots.size(); ++jct) {
2445 auto& jss = slc.
cots[jct];
2446 if (jss.ID == 0)
continue;
2447 if (jss.TjIDs.empty())
continue;
2448 if (jss.CTP != iss.CTP)
continue;
2449 if (
DontCluster(slc, iss.TjIDs, jss.TjIDs))
continue;
2450 bool doMerge =
false;
2451 for (
auto& ivx : iss.Envelope) {
2456 for (
auto& jvx : jss.Envelope) {
2463 for (
auto& ivx : iss.Envelope) {
2464 for (
auto& jvx : jss.Envelope) {
2465 if (
PosSep2(ivx, jvx) < sepCut2) {
2467 mf::LogVerbatim(
"TC")
2468 << fcnLabel <<
" Envelopes 2S" << iss.ID <<
" 2S" << jss.ID <<
" are close "
2477 if (!doMerge)
continue;
2481 unsigned short iClosePt = 0;
2482 unsigned short jClosePt = 0;
2484 auto& istj = slc.
tjs[iss.ShowerTjID - 1];
2485 auto& jstj = slc.
tjs[jss.ShowerTjID - 1];
2486 for (
unsigned short ipt = 0; ipt < 3; ++ipt) {
2487 for (
unsigned short jpt = 0; jpt < 3; ++jpt) {
2488 float sep =
PosSep2(istj.Pts[ipt].Pos, jstj.Pts[jpt].Pos);
2496 float costh =
DotProd(istj.Pts[0].Dir, jstj.Pts[0].Dir);
2497 if (iClosePt == 0 && jClosePt == 0 && costh < 0.955) {
2499 mf::LogVerbatim(
"TC")
2500 << fcnLabel <<
" showers are close at the start points with costh " << costh
2504 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Merge " << iss.ID <<
" and " << jss.ID;
2512 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Merge failed";
2530 std::string fcnLabel = inFcnLabel +
".MSC";
2532 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
": MergeShowerChain inCTP " << inCTP;
2534 std::vector<int> sids;
2535 std::vector<TrajPoint> tpList;
2536 for (
unsigned short ict = 0; ict < slc.
cots.size(); ++ict) {
2538 if (iss.
ID == 0)
continue;
2539 if (iss.
TjIDs.empty())
continue;
2540 if (iss.
CTP != inCTP)
continue;
2542 if (iss.
Energy < 50)
continue;
2544 sids.push_back(iss.
ID);
2548 if (sids.size() < 3)
return;
2551 std::vector<SortEntry> sortVec(sids.size());
2552 for (
unsigned short ii = 0; ii < sortVec.size(); ++ii) {
2553 sortVec[ii].index = ii;
2554 sortVec[ii].val = tpList[ii].Pos[0];
2558 auto ttpList = tpList;
2559 for (
unsigned short ii = 0; ii < sortVec.size(); ++ii) {
2560 unsigned short indx = sortVec[ii].index;
2561 sids[ii] = tsids[indx];
2562 tpList[ii] = ttpList[indx];
2567 float maxDelta = 30;
2568 for (
unsigned short ii = 0; ii < sids.size() - 2; ++ii) {
2569 auto& iss = slc.
cots[sids[ii] - 1];
2570 if (iss.ID == 0)
continue;
2571 unsigned short jj = ii + 1;
2572 auto& jss = slc.
cots[sids[jj] - 1];
2573 if (jss.ID == 0)
continue;
2574 std::vector<int> chain;
2575 float sepij =
PosSep(tpList[ii].Pos, tpList[jj].Pos);
2576 if (sepij > minSep)
continue;
2577 bool skipit =
DontCluster(slc, iss.TjIDs, jss.TjIDs);
2579 mf::LogVerbatim(
"TC") << fcnLabel <<
" i2S" << iss.ID <<
" "
2580 <<
PrintPos(slc, tpList[ii].Pos) <<
" j2S" << jss.ID <<
" "
2581 <<
PrintPos(slc, tpList[jj].Pos) <<
" sepij " << sepij <<
" skipit? "
2583 if (skipit)
continue;
2587 for (
unsigned short kk = jj + 1; kk < sids.size(); ++kk) {
2588 auto& kss = slc.
cots[sids[kk] - 1];
2589 if (kss.ID == 0)
continue;
2590 if (
DontCluster(slc, iss.TjIDs, kss.TjIDs))
continue;
2591 if (
DontCluster(slc, jss.TjIDs, kss.TjIDs))
continue;
2592 float sepjk =
PosSep(tpList[jj].Pos, tpList[kk].Pos);
2593 float delta =
PointTrajDOCA(slc, tpList[kk].Pos[0], tpList[kk].Pos[1], tp);
2595 mf::LogVerbatim myprt(
"TC");
2596 myprt << fcnLabel <<
" k2S" << kss.ID <<
" " <<
PrintPos(slc, tpList[kk].Pos)
2597 <<
" sepjk " << sepjk <<
" delta " << delta;
2598 if (sepjk > minSep || delta > maxDelta) {
2599 myprt <<
" failed separation " << minSep <<
" or delta cut " << maxDelta;
2602 myprt <<
" add to the chain";
2605 if (sepjk > minSep || delta > maxDelta) {
2607 if (chain.size() > 2) {
2611 mf::LogVerbatim myprt(
"TC");
2612 myprt << fcnLabel <<
" merged chain";
2613 for (
auto ssID : chain)
2614 myprt <<
" 2S" << ssID;
2615 myprt <<
" -> 2S" << newID;
2623 if (chain.empty()) {
2625 chain[0] = sids[ii];
2626 chain[1] = sids[jj];
2627 chain[2] = sids[kk];
2630 chain.push_back(sids[kk]);
2637 if (chain.size() > 2) {
2640 mf::LogVerbatim myprt(
"TC");
2641 myprt << fcnLabel <<
" merged chain";
2642 for (
auto ssID : chain)
2643 myprt <<
" " << ssID;
2644 myprt <<
" -> new ssID " << newID;
2662 std::string fcnLabel = inFcnLabel +
".MSSTj";
2669 std::vector<TjSS> tjss;
2672 std::vector<int> tjid(1);
2673 for (
auto& ss : slc.
cots) {
2674 if (ss.ID == 0)
continue;
2675 if (ss.CTP != inCTP)
continue;
2677 if (ss.Energy > 300)
continue;
2678 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
2679 auto stp0 = stj.Pts[0];
2680 float bestDang = 0.3;
2683 for (
auto& tj : slc.
tjs) {
2684 if (tj.AlgMod[
kKilled])
continue;
2685 if (tj.AlgMod[
kHaloTj])
continue;
2686 if (tj.CTP != ss.CTP)
continue;
2688 if (tj.SSID > 0)
continue;
2696 float tjEnergy =
ChgToMeV(tj.TotChg);
2698 unsigned short farEnd =
FarEnd(slc, tj, stj.Pts[1].Pos);
2700 unsigned short midpt = 0.5 * (tj.EndPt[0] + tj.EndPt[1]);
2701 float mom1 =
MCSMom(slc, tj, tj.EndPt[farEnd], midpt);
2702 float mom2 =
MCSMom(slc, tj, tj.EndPt[1 - farEnd], midpt);
2703 float asym = (mom1 - mom2) / (mom1 + mom2);
2704 auto& farTP = tj.Pts[tj.EndPt[farEnd]];
2706 float doca =
PointTrajDOCA(slc, stp0.Pos[0], stp0.Pos[1], farTP);
2707 float sep =
PosSep(farTP.Pos, stp0.Pos);
2708 float dang = doca / sep;
2710 mf::LogVerbatim myprt(
"TC");
2711 myprt << fcnLabel <<
" Candidate 2S" << ss.ID <<
" T" << tj.ID <<
"_" << farEnd;
2712 myprt <<
" ShEnergy " << (int)ss.Energy <<
" tjEnergy " << (
int)tjEnergy;
2713 myprt <<
" doca " << doca <<
" sep " << sep <<
" dang " << dang <<
" asym " << asym;
2715 if (tjEnergy < ss.Energy)
continue;
2716 if (asym < 0.5)
continue;
2719 if (sep > 100)
continue;
2720 if (dang > bestDang)
continue;
2724 if (bestTj == 0)
continue;
2727 match.tjID = bestTj;
2728 match.dang = bestDang;
2729 tjss.push_back(match);
2732 if (tjss.empty())
return;
2735 bool keepGoing =
true;
2738 float bestDang = 0.3;
2740 for (
unsigned short mat = 0; mat < tjss.size(); ++mat) {
2741 auto& match = tjss[mat];
2743 if (match.dang < 0)
continue;
2744 if (match.dang < bestDang) bestMatch = mat;
2746 if (bestMatch > 0) {
2747 auto& match = tjss[bestMatch];
2748 auto& ss = slc.
cots[match.ssID - 1];
2749 if (!
AddTj(fcnLabel, slc, match.tjID, ss,
true, prt)) {
2750 if (prt) mf::LogVerbatim(
"TC") <<
" Failed";
2755 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
2773 std::string fcnLabel = inFcnLabel +
".MSS";
2775 constexpr
float radLen = 14 / 0.3;
2779 mf::LogVerbatim(
"TC") << fcnLabel <<
" MergeSubShowers checking using ShowerParams";
2782 mf::LogVerbatim(
"TC") << fcnLabel
2783 <<
" MergeSubShowers checking using radiation length cut ";
2787 bool keepMerging =
true;
2788 while (keepMerging) {
2789 keepMerging =
false;
2791 std::vector<SortEntry> sortVec;
2792 for (
auto& ss : slc.
cots) {
2793 if (ss.ID == 0)
continue;
2794 if (ss.CTP != inCTP)
continue;
2796 se.
index = ss.ID - 1;
2798 sortVec.push_back(se);
2800 if (sortVec.size() < 2)
return;
2802 for (
unsigned short ii = 0; ii < sortVec.size() - 1; ++ii) {
2804 if (iss.
ID == 0)
continue;
2808 double shMaxAlong, along95;
2811 along95 -= shMaxAlong;
2814 for (
unsigned short jj = ii + 1; jj < sortVec.size(); ++jj) {
2816 if (jss.
ID == 0)
continue;
2825 if (alongTrans[0] < 0)
continue;
2827 float alongCut = along95;
2832 mf::LogVerbatim myprt(
"TC");
2833 myprt << fcnLabel <<
" Candidate i2S" << iss.
ID <<
" E = " << (int)iss.
Energy
2834 <<
" j2S" << jss.
ID <<
" E = " << (
int)jss.
Energy;
2835 myprt <<
" along " << std::fixed << std::setprecision(1) << alongTrans[0] <<
" trans "
2837 myprt <<
" alongCut " << alongCut <<
" probLong " << probLong <<
" probTran "
2840 if (alongTrans[0] > alongCut)
continue;
2841 if (alongTrans[1] > alongTrans[0])
continue;
2846 float trad = sep / radLen;
2856 float dang = delta / sep;
2858 mf::LogVerbatim(
"TC") << fcnLabel <<
" Candidate i2S" << iss.
ID <<
" j2S" << jss.
ID
2859 <<
" separation " << (int)sep <<
" radiation lengths " << trad
2860 <<
" delta " << delta <<
" dang " << dang;
2861 if (trad > 3)
continue;
2863 if (dang > 0.3)
continue;
2866 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Merge them. Re-find shower center, etc";
2874 if (keepMerging)
break;
2889 std::string fcnLabel = inFcnLabel +
".MS";
2890 if (ssIDs.size() < 2)
return 0;
2892 for (
auto ssID : ssIDs)
2893 if (ssID <= 0 || ssID > (
int)slc.
cots.size())
return 0;
2896 auto& ss0 = slc.
cots[ssIDs[0] - 1];
2897 std::vector<int> tjl;
2898 for (
auto ssID : ssIDs) {
2899 auto& ss = slc.
cots[ssID - 1];
2900 if (ss.CTP != ss0.CTP)
return 0;
2901 tjl.insert(tjl.end(), ss.TjIDs.begin(), ss.TjIDs.end());
2902 if (ss.SS3ID > 0 && ss3Assn == 0) ss3Assn = ss.SS3ID;
2903 if (ss.SS3ID > 0 && ss.SS3ID != ss3Assn)
return 0;
2906 for (
auto tjID : tjl) {
2907 auto& tj = slc.
tjs[tjID - 1];
2908 if (tj.CTP != ss0.CTP || tj.AlgMod[
kKilled])
return 0;
2912 for (
auto ssID : ssIDs) {
2913 auto& ss = slc.
cots[ssID - 1];
2916 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
2922 if (newss.ID == 0)
return 0;
2924 for (
auto tid : tjl) {
2925 auto& tj = slc.
tjs[tid - 1];
2928 newss.SS3ID = ss3Assn;
2952 if (icotID <= 0 || icotID > (
int)slc.
cots.size())
return false;
2954 if (iss.
ID == 0)
return false;
2955 if (iss.
TjIDs.empty())
return false;
2958 if (jcotID <= 0 || jcotID > (
int)slc.
cots.size())
return false;
2960 if (jss.
TjIDs.empty())
return false;
2961 if (jss.
ID == 0)
return false;
2964 if (iss.
CTP != jss.
CTP)
return false;
2966 std::string fcnLabel = inFcnLabel +
".MSAS";
2972 if (!itj.
Pts[1].Hits.empty() || !jtj.
Pts[1].Hits.empty())
return false;
2977 ktj.
ID = slc.
tjs.size() + 1;
2979 slc.
tjs.push_back(ktj);
2986 mf::LogVerbatim(
"TC") << fcnLabel <<
" killed stj T" << iss.
ShowerTjID <<
" and T"
2992 std::sort(iss.
TjIDs.begin(), iss.
TjIDs.end());
2994 for (
auto tid : iss.
TjIDs) {
2995 auto& tj = slc.
tjs[tid - 1];
3024 if (istj > slc.
tjs.size() - 1)
return false;
3025 if (jstj > slc.
tjs.size() - 1)
return false;
3030 std::string fcnLabel =
"MSTJ";
3033 mf::LogVerbatim(
"TC") << fcnLabel <<
" MergeShowerTjsAndStore Tj IDs " << itj.
ID <<
" "
3038 if (prt) mf::LogVerbatim(
"TC") <<
" One of these isn't a shower Tj";
3046 if (icotID == 0)
return false;
3048 if (iss.
ID == 0)
return false;
3049 if (iss.
TjIDs.empty())
return false;
3051 if (jcotID == 0)
return false;
3053 if (jss.
ID == 0)
return false;
3054 if (jss.
TjIDs.empty())
return false;
3069 if (ss.
ID == 0)
return false;
3070 if (ss.
ShPts.empty())
return false;
3072 if (stj.
Pts.size() != 3)
return false;
3074 std::string fcnLabel = inFcnLabel +
".ARP";
3076 for (
auto& tp : stj.
Pts) {
3080 tp.HitPos = {{0.0, 0.0}};
3083 float minAlong = ss.
ShPts[0].RotPos[0];
3084 float maxAlong = ss.
ShPts[ss.
ShPts.size() - 1].RotPos[0];
3085 float sectionLength = (maxAlong - minAlong) / 3;
3086 float sec0 = minAlong + sectionLength;
3087 float sec2 = maxAlong - sectionLength;
3089 for (
auto& spt : ss.
ShPts) {
3091 unsigned short ipt = 0;
3092 if (spt.RotPos[0] < sec0) {
3096 else if (spt.RotPos[0] > sec2) {
3104 stj.
Pts[ipt].Chg += spt.Chg;
3109 stj.
Pts[ipt].DeltaRMS += spt.Chg *
std::abs(spt.RotPos[1]);
3110 ++stj.
Pts[ipt].NTPsFit;
3112 stj.
Pts[ipt].HitPos[0] += spt.Chg * spt.Pos[0];
3113 stj.
Pts[ipt].HitPos[1] += spt.Chg * spt.Pos[1];
3116 for (
auto& tp : stj.
Pts) {
3118 tp.DeltaRMS /= tp.Chg;
3119 tp.HitPos[0] /= tp.Chg;
3120 tp.HitPos[1] /= tp.Chg;
3126 if (stj.
Pts[0].Chg == 0 || stj.
Pts[2].Chg == 0)
return false;
3129 if (stj.
Pts[1].Chg == 0) {
3131 stj.
Pts[1].HitPos[0] = 0.5 * (stj.
Pts[0].HitPos[0] + stj.
Pts[2].HitPos[0]);
3132 stj.
Pts[1].HitPos[1] = 0.5 * (stj.
Pts[0].HitPos[1] + stj.
Pts[2].HitPos[1]);
3139 mf::LogVerbatim myprt(
"TC");
3140 myprt << fcnLabel <<
" 2S" << ss.
ID;
3141 myprt <<
" HitPos[0] " << std::fixed << std::setprecision(1);
3142 myprt << stj.
Pts[1].HitPos[0] <<
" " << stj.
Pts[1].HitPos[1] <<
" " << stj.
Pts[1].HitPos[2];
3143 myprt <<
" DeltaRMS " << std::setprecision(2);
3144 myprt << stj.
Pts[0].DeltaRMS <<
" " << stj.
Pts[1].DeltaRMS <<
" " << stj.
Pts[2].DeltaRMS;
3145 myprt <<
" DirectionFOM " << std::fixed << std::setprecision(2) << ss.
DirectionFOM;
3157 if (ss.
ID == 0)
return;
3158 if (ss.
TjIDs.empty())
return;
3160 std::string fcnLabel = inFcnLabel +
".RevSh";
3162 std::reverse(ss.
ShPts.begin(), ss.
ShPts.end());
3164 for (
auto& sspt : ss.
ShPts) {
3165 sspt.RotPos[0] = -sspt.RotPos[0];
3166 sspt.RotPos[1] = -sspt.RotPos[1];
3177 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Reversed shower. Shower angle = " << ss.
Angle;
3186 if (cotID > (
int)slc.
cots.size())
return;
3188 if (ss.
ID == 0)
return;
3198 for (
auto cid : ss3.
CotIDs) {
3199 if (cid == 0 || (
unsigned short)cid > slc.
cots.size())
continue;
3200 auto& ss = slc.
cots[cid - 1];
3201 if (ss.SS3ID > 0 && ss.SS3ID != ss3.
ID)
continue;
3205 std::string fcnLabel = inFcnLabel +
".MSO";
3206 mf::LogVerbatim(
"TC") << fcnLabel <<
" Killed 3S" << ss3.
ID;
3217 if (ss.
ID == 0)
return;
3219 std::string fcnLabel = inFcnLabel +
".MSO";
3222 if (!stp1.Hits.empty())
return;
3227 std::vector<int> newCIDs;
3228 for (
auto cid : ss3.CotIDs) {
3229 if (cid != ss.
ID) newCIDs.push_back(cid);
3231 ss3.CotIDs = newCIDs;
3239 for (
auto& tjID : ss.
TjIDs) {
3251 mf::LogVerbatim(
"TC") << fcnLabel <<
" Killed 2S" << ss.
ID <<
" and ST" << ss.
ShowerTjID;
3261 if (tjlist1.empty() || tjlist2.empty())
return false;
3263 for (
auto tid1 : tjlist1) {
3264 for (
auto tid2 : tjlist2) {
3266 if (ttid1 > tid2) std::swap(ttid1, tid2);
3268 if (dc.TjIDs[0] == ttid1 && dc.TjIDs[1] == tid2)
return true;
3282 if (slc.
tjs.size() > 20000)
return;
3288 std::vector<std::vector<int>> tjLists;
3289 std::vector<int> tjids;
3290 for (
auto& tj : slc.
tjs) {
3291 if (tj.CTP != inCTP)
continue;
3292 if (tj.AlgMod[
kKilled])
continue;
3293 if (tj.AlgMod[
kHaloTj])
continue;
3297 bool skipit =
false;
3298 for (
unsigned short end = 0;
end < 2; ++
end)
3299 if (tj.EndFlag[
end][
kBragg]) skipit =
true;
3300 if (skipit)
continue;
3304 if (npwc > 100)
continue;
3311 if (tj.ChgRMS > typicalChgRMS) momCut *= tj.ChgRMS / typicalChgRMS;
3312 if (tj.MCSMom > momCut)
continue;
3314 tjids.push_back(tj.ID);
3317 if (tjids.size() < 2)
return;
3319 for (
unsigned short it1 = 0; it1 < tjids.size() - 1; ++it1) {
3321 for (
unsigned short it2 = it1 + 1; it2 < tjids.size(); ++it2) {
3323 unsigned short ipt1, ipt2;
3330 bool inlist =
false;
3331 for (
unsigned short it = 0; it < tjLists.size(); ++it) {
3333 (std::find(tjLists[it].
begin(), tjLists[it].
end(), tj1.
ID) != tjLists[it].end());
3335 (std::find(tjLists[it].
begin(), tjLists[it].
end(), tj2.
ID) != tjLists[it].end());
3336 if (tj1InList || tj2InList) {
3338 if (!tj1InList) tjLists[it].push_back(tj1.
ID);
3339 if (!tj2InList) tjLists[it].push_back(tj2.
ID);
3347 std::vector<int> newlist(2);
3348 newlist[0] = tj1.
ID;
3349 newlist[1] = tj2.
ID;
3350 tjLists.push_back(newlist);
3354 if (tjLists.empty())
return;
3357 for (
auto& tjl : tjLists) {
3359 if (tjl.size() < 3)
continue;
3360 for (
auto& tjID : tjl) {
3361 auto& tj = slc.
tjs[tjID - 1];
3367 unsigned short nsh = 0;
3368 for (
auto& tjl : tjLists) {
3369 for (
auto& tjID : tjl) {
3370 auto& tj = slc.
tjs[tjID - 1];
3374 mf::LogVerbatim(
"TC") <<
"TagShowerLike tagged " << nsh <<
" Tjs vertices in CTP " << inCTP;
3389 std::string fcnLabel = inFcnLabel +
".FNTj";
3391 std::vector<int> ntj;
3394 constexpr
float fiveRadLen = 200;
3397 for (
auto vx : slc.
vtxs) {
3398 if (vx.CTP != ss.
CTP)
continue;
3399 if (vx.ID == 0)
continue;
3401 auto vxTjIDs =
GetAssns(slc,
"2V", vx.
ID,
"T");
3402 for (
auto tjID : vxTjIDs) {
3404 if (std::find(ss.
TjIDs.begin(), ss.
TjIDs.end(), tjID) != ss.
TjIDs.end())
continue;
3406 if (std::find(ntj.begin(), ntj.end(), tjID) != ntj.end())
continue;
3407 ntj.push_back(tjID);
3412 for (
auto& tj : slc.
tjs) {
3413 if (tj.CTP != ss.
CTP)
continue;
3414 if (tj.AlgMod[
kKilled])
continue;
3418 if (std::find(ss.
TjIDs.begin(), ss.
TjIDs.end(), tj.ID) != ss.
TjIDs.end())
continue;
3420 if (std::find(ntj.begin(), ntj.end(), tj.ID) != ntj.end())
continue;
3422 if (tj.Pts.size() > 40 && tj.MCSMom > 200) {
3423 float delta =
PointTrajDOCA(slc, stj.Pts[1].Pos[0], stj.Pts[1].Pos[1], tj.Pts[tj.EndPt[0]]);
3426 float doca = fiveRadLen;
3427 unsigned short spt = 0, ipt = 0;
3429 if (doca < fiveRadLen) {
3430 ntj.push_back(tj.ID);
3436 bool isInside =
false;
3437 for (
unsigned short ipt = tj.EndPt[0]; ipt < tj.EndPt[1]; ipt += 3) {
3445 unsigned short ipt = tj.EndPt[1];
3448 if (isInside) ntj.push_back(tj.ID);
3450 if (ntj.size() > 1) std::sort(ntj.begin(), ntj.end());
3452 mf::LogVerbatim(
"TC") << fcnLabel <<
" Found " << ntj.size() <<
" Tjs near ss.ID " << ss.
ID;
3463 if (itj > slc.
tjs.size() - 1)
return;
3468 for (
auto& tp : slc.
tjs[itj].Pts) {
3469 for (
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
3471 if (tp.UseHit[ii])
continue;
3472 unsigned int iht = tp.Hits[ii];
3474 if (slc.
slHits[iht].InTraj <= 0)
continue;
3475 if ((
unsigned int)slc.
slHits[iht].InTraj > slc.
tjs.size())
continue;
3478 if (tj.
MCSMom > maxMom)
continue;
3481 if (std::find(list.begin(), list.end(), slc.
slHits[iht].InTraj) != list.end())
continue;
3482 list.push_back(slc.
slHits[iht].InTraj);
3492 if (ss.
ID == 0)
return;
3493 if (ss.
TjIDs.empty())
return;
3496 if (stj.
Pts[0].Pos[0] == 0)
return;
3498 std::string fcnLabel = inFcnLabel +
".DE";
3525 float cs = cos(stp1.
Ang);
3526 float sn = sin(stp1.
Ang);
3529 float pos0 = cs * vtx[0] - sn * vtx[1];
3530 float pos1 = sn * vtx[0] + cs * vtx[1];
3532 vtx[0] = pos0 + stp1.
Pos[0];
3533 vtx[1] = pos1 + stp1.
Pos[1];
3538 mf::LogVerbatim myprt(
"TC");
3539 myprt << fcnLabel <<
" 2S" << ss.
ID <<
" Envelope";
3541 myprt <<
" " << (int)vtx[0] <<
":" << (
int)(vtx[1] /
tcc.
unitsPerTick);
3555 if (ss.
Envelope.empty())
return false;
3556 if (ss.
ID == 0)
return false;
3557 if (ss.
TjIDs.empty())
return false;
3559 std::string fcnLabel = inFcnLabel +
".ATIE";
3561 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Checking 2S" << ss.
ID;
3563 std::vector<int> tmp(1);
3564 unsigned short nadd = 0;
3565 for (
auto& tj : slc.
tjs) {
3566 if (tj.CTP != ss.
CTP)
continue;
3567 if (tj.AlgMod[
kKilled])
continue;
3568 if (tj.SSID > 0)
continue;
3571 if (tj.ParentID == 0)
continue;
3573 if (neutPrimTj > 0 && neutPrimTj != tj.ID) {
3580 if (std::find(ss.
TjIDs.begin(), ss.
TjIDs.end(), tj.ID) != ss.
TjIDs.end())
continue;
3587 if (!end0Inside && !end1Inside)
continue;
3588 if (end0Inside && end1Inside) {
3590 if (
AddTj(fcnLabel, slc, tj.
ID, ss,
false, prt)) ++nadd;
3597 if (tj.MCSMom > 200) {
3598 float tjAngle = tj.Pts[tj.EndPt[0]].Ang;
3601 mf::LogVerbatim(
"TC") << fcnLabel <<
" high MCSMom " << tj.MCSMom <<
" dangPull "
3603 if (dangPull > 2)
continue;
3605 if (
AddTj(fcnLabel, slc, tj.
ID, ss,
false, prt)) { ++nadd; }
3607 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" AddTj failed to add T" << tj.ID;
3612 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" Added " << nadd <<
" trajectories ";
3618 if (prt) mf::LogVerbatim(
"TC") << fcnLabel <<
" No new trajectories added to envelope ";
3634 if (ss.
Envelope.empty())
return false;
3635 if (ss.
ID == 0)
return false;
3636 if (ss.
TjIDs.empty())
return false;
3639 unsigned short ipl = planeID.
Plane;
3644 std::vector<unsigned int> newHits;
3647 float fLoWire = 1E6;
3653 if (vtx[0] < fLoWire) fLoWire = vtx[0];
3654 if (vtx[0] > fHiWire) fHiWire = vtx[0];
3655 if (vtx[1] < loTick) loTick = vtx[1];
3656 if (vtx[1] > hiTick) hiTick = vtx[1];
3660 unsigned int loWire = std::nearbyint(fLoWire);
3661 unsigned int hiWire = std::nearbyint(fHiWire) + 1;
3663 std::array<float, 2> point;
3664 for (
unsigned int wire = loWire; wire < hiWire; ++wire) {
3666 if (slc.
wireHitRange[ipl][wire].first == UINT_MAX)
continue;
3667 unsigned int firstHit = slc.
wireHitRange[ipl][wire].first;
3668 unsigned int lastHit = slc.
wireHitRange[ipl][wire].second;
3669 for (
unsigned int iht = firstHit; iht < lastHit; ++iht) {
3671 if (slc.
slHits[iht].InTraj != 0)
continue;
3674 if (
hit.PeakTime() < loTick)
continue;
3676 if (
hit.PeakTime() > hiTick)
break;
3678 point[0] =
hit.WireID().Wire;
3681 newHits.push_back(iht);
3686 if (newHits.empty()) {
3687 if (prt) mf::LogVerbatim(
"TC") <<
"ALH: No new loose hits found";
3692 stp0.
Hits.insert(stp0.
Hits.end(), newHits.begin(), newHits.end());
3693 for (
auto& iht : newHits)
3697 mf::LogVerbatim(
"TC") <<
"ALH: Added " << stp0.
Hits.size() <<
" hits to stj " << stj.
ID;
3708 if (cotID > (
int)slc.
cots.size())
return;
3711 if (ss.
ID == 0)
return;
3712 if (ss.
TjIDs.empty())
return;
3717 std::string fcnLabel = inFcnLabel +
".FSC";
3723 mf::LogVerbatim(
"TC") << fcnLabel <<
" Not possible due to poor AspectRatio "
3730 if (schg.empty())
return;
3734 unsigned short startPt = USHRT_MAX;
3736 for (
unsigned short ii = 0; ii < schg.size() - 1; ++ii) {
3737 if (schg[ii] > 0 && schg[ii + 1] > 0) {
3743 if (startPt == USHRT_MAX)
return;
3749 for (
unsigned short ii = startPt; ii < schg.size() - 1; ++ii) {
3751 rms += schg[ii] * schg[ii];
3755 rms = rms - cnt * ave * ave;
3756 if (rms < 0)
return;
3757 rms = sqrt(rms / (cnt - 1));
3760 mf::LogVerbatim myprt(
"TC");
3761 myprt << fcnLabel <<
" schg:";
3762 for (
unsigned short ii = 0; ii < 20; ++ii)
3763 myprt <<
" " << (
int)schg[ii];
3764 myprt <<
"\n First guess at the charge " << (int)chg <<
" average charge of all bins "
3765 << (
int)ave <<
" rms " << (int)rms;
3771 unsigned short nBinsAverage = 5;
3772 double maxChg = 2 * chg;
3773 for (
unsigned short nit = 0; nit < 2; ++nit) {
3777 for (
unsigned short ii = startPt; ii < schg.size() - 1; ++ii) {
3779 if (schg[ii] > maxChg && schg[ii + 1] > maxChg)
break;
3781 if (schg[ii] == 0 && schg[ii + 1] == 0)
break;
3782 if (schg[ii] > maxChg)
continue;
3784 sum2 += schg[ii] * schg[ii];
3786 if (cnt == nBinsAverage)
break;
3791 mf::LogVerbatim(
"TC") << fcnLabel <<
" nit " << nit <<
" cnt " << cnt
3792 <<
" is too low. sum " << (int)sum <<
" maxChg " << (
int)maxChg;
3795 chg = schg[startPt];
3801 double arg = sum2 - cnt * chg * chg;
3803 rms = sqrt(arg / (cnt - 1));
3805 double maxrms = 0.5 * sum;
3806 if (rms > maxrms) rms = maxrms;
3807 maxChg = chg + 2 * rms;
3809 mf::LogVerbatim(
"TC") << fcnLabel <<
" nit " << nit <<
" cnt " << cnt <<
" chg " << (int)chg
3810 <<
" rms " << (
int)rms <<
" maxChg " << (int)maxChg
3811 <<
" nBinsAverage " << nBinsAverage;
3818 mf::LogVerbatim(
"TC") << fcnLabel <<
" 2S" << cotID <<
" Starting charge " << (int)stp0.AveChg
3819 <<
" startPt " << startPt;
3830 constexpr
unsigned short nbins = 20;
3831 std::vector<float> schg(nbins);
3832 if (ss.
ID == 0)
return schg;
3833 if (ss.
TjIDs.empty())
return schg;
3838 float minAlong = ss.
ShPts[0].RotPos[0] - 2;
3843 float cs = cos(-ss.
Angle);
3844 float sn = sin(-ss.
Angle);
3845 std::array<float, 2> chgPos;
3848 for (
auto& sspt : ss.
ShPts) {
3849 unsigned short indx = (
unsigned short)((sspt.RotPos[0] - minAlong));
3850 if (indx > nbins - 1)
break;
3852 if (
std::abs(sspt.RotPos[1]) > maxTrans)
continue;
3853 unsigned int iht = sspt.HitIndex;
3855 float peakTime =
hit.PeakTime();
3856 float amp =
hit.PeakAmplitude();
3857 float rms =
hit.RMS();
3858 chgPos[0] =
hit.WireID().Wire - stp1.
Pos[0];
3859 for (
float time = peakTime - 2.5 * rms; time < peakTime + 2.5 * rms; ++time) {
3861 along = cs * chgPos[0] - sn * chgPos[1];
3862 if (along < minAlong)
continue;
3863 indx = (
unsigned short)(along - minAlong);
3864 if (indx > nbins - 1)
continue;
3865 arg = (time - peakTime) / rms;
3866 schg[indx] += amp *
exp(-0.5 * arg * arg);
3881 if (cotID > (
int)slc.
cots.size())
return;
3884 if (ss.
ID == 0)
return;
3885 if (ss.
TjIDs.empty())
return;
3886 std::cout <<
"PTS Pos0 Pos1 RPos0 RPos1 Chg TID\n";
3887 for (
auto& pt : ss.
ShPts) {
3888 std::cout <<
"PTS " << std::fixed << std::setprecision(1) << pt.Pos[0] <<
" " << pt.Pos[1]
3889 <<
" " << pt.RotPos[0] <<
" " << pt.RotPos[1];
3890 std::cout <<
" " << (int)pt.Chg <<
" " << pt.TID;
3902 bool newShowers =
false;
3903 for (
auto& ss : slc.
cots) {
3904 if (ss.ID == 0)
continue;
3905 if (ss.ShowerTjID == 0)
continue;
3908 if (!stj.
Pts[1].Hits.empty()) {
3909 std::cout <<
"TTjH: ShowerTj T" << stj.
ID <<
" already has " << stj.
Pts[1].Hits.size()
3914 for (
auto& tjID : ss.TjIDs) {
3915 unsigned short itj = tjID - 1;
3917 std::cout <<
"TTjH: Coding error. T" << tjID <<
" is a ShowerTj but is in TjIDs\n";
3920 if (slc.
tjs[itj].SSID <= 0) {
3921 std::cout <<
"TTjH: Coding error. Trying to transfer T" << tjID
3922 <<
" hits but it isn't an InShower Tj\n";
3927 stj.
Pts[1].Hits.insert(stj.
Pts[1].Hits.end(), thits.begin(), thits.end());
3932 for (
auto& iht : stj.
Pts[1].Hits)
3937 if (prt) mf::LogVerbatim(
"TC") <<
"TTJH: success? " << newShowers;
3945 for (
unsigned short ii = 0; ii < slc.
cots.size(); ++ii) {
3946 if (ShowerTjID == slc.
cots[ii].ShowerTjID)
return ii + 1;
3956 if (ss3.
ID == 0)
return 0;
3957 if (ss3.
Energy.empty())
return 0;
3962 ave /= ss3.
Energy.size();
3971 if (tjIDs.empty())
return 0;
3973 for (
auto tid : tjIDs) {
3974 auto& tj = slc.
tjs[tid - 1];
3996 std::string fcnLabel = inFcnLabel +
".S3S";
4001 if (ss3.
CotIDs.size() < 2) {
4002 std::cout << fcnLabel <<
" not enough CotIDs";
4007 for (
auto& ss : slc.
cots) {
4008 if (ss.ID == 0)
continue;
4009 if (ss.SS3ID == ss3.
ID &&
4011 std::cout << fcnLabel <<
" Bad assn: 2S" << ss.ID <<
" -> 3S" << ss3.
ID
4012 <<
" but it's not inCotIDs.\n";
4018 for (
auto cid : ss3.
CotIDs) {
4019 if (cid <= 0 || cid > (
int)slc.
cots.size())
return false;
4020 auto& ss = slc.
cots[cid - 1];
4021 if (ss.SS3ID > 0 && ss.SS3ID != ss3.
ID) {
4022 std::cout << fcnLabel <<
" Bad assn: 3S" << ss3.
ID <<
" -> 2S" << cid <<
" but 2S -> 3S"
4023 << ss.SS3ID <<
"\n";
4029 for (
auto cid : ss3.
CotIDs)
4030 slc.
cots[cid - 1].SS3ID = ss3.
ID;
4045 std::string fcnLabel = inFcnLabel +
".S2S";
4050 if (ss.
TjIDs.empty()) {
4051 std::cout << fcnLabel <<
" Fail: No TjIDs in 2S" << ss.
ID <<
"\n";
4056 std::cout << fcnLabel <<
" Fail: 2S" << ss.
ID <<
" has an invalid ParentID T" << ss.
ParentID
4061 std::cout << fcnLabel <<
" Fail: 2S" << ss.
ID <<
" ParentID is not in TjIDs.\n";
4067 if (ss.
ID != (
int)slc.
cots.size() + 1) {
4068 std::cout << fcnLabel <<
" Correcting the ID 2S" << ss.
ID <<
" -> 2S" << slc.
cots.size() + 1;
4069 ss.
ID = slc.
cots.size() + 1;
4073 for (
auto& tjID : ss.
TjIDs) {
4083 slc.
cots.push_back(ss);
4119 stj.
CTP = slc.
tjs[tjl[0] - 1].CTP;
4123 for (
auto& stp : stj.
Pts) {
4130 stj.
ID = slc.
tjs.size() + 1;
4134 slc.
tjs.push_back(stj);
4136 ss.
ID = slc.
cots.size() + 1;
4141 for (
auto tjid : tjl) {
4142 auto& tj = slc.
tjs[tjid - 1];
4143 if (tj.CTP != stj.
CTP) {
4161 std::string fcnLabel = inFcnLabel +
".ChkAssns";
4162 for (
auto& ss : slc.
cots) {
4163 if (ss.ID == 0)
continue;
4164 for (
auto tid : ss.TjIDs) {
4165 auto& tj = slc.
tjs[tid - 1];
4166 if (tj.SSID != ss.ID) {
4167 std::cout << fcnLabel <<
" ***** Error: 2S" << ss.ID <<
" -> TjIDs T" << tid
4168 <<
" != tj.SSID 2S" << tj.SSID <<
"\n";
4173 if (ss.SS3ID > 0 && ss.SS3ID <= (
int)slc.
showers.size()) {
4174 auto& ss3 = slc.
showers[ss.SS3ID - 1];
4175 if (std::find(ss3.CotIDs.begin(), ss3.CotIDs.end(), ss.ID) == ss3.CotIDs.end()) {
4176 std::cout << fcnLabel <<
" ***** Error: 2S" << ss.ID <<
" -> 3S" << ss.SS3ID
4177 <<
" but the shower says no\n";
4182 for (
auto& tj : slc.
tjs) {
4183 if (tj.AlgMod[
kKilled])
continue;
4185 std::cout << fcnLabel <<
" ***** Error: T" << tj.ID <<
" tj.SSID is fubar\n";
4189 if (tj.SSID == 0)
continue;
4190 auto& ss = slc.
cots[tj.SSID - 1];
4191 if (std::find(ss.TjIDs.begin(), ss.TjIDs.end(), tj.ID) != ss.TjIDs.end())
continue;
4192 std::cout << fcnLabel <<
" ***** Error: T" << tj.ID <<
" tj.SSID = 2S" << tj.SSID
4193 <<
" but the shower says no\n";
4197 for (
auto& ss3 : slc.
showers) {
4198 if (ss3.ID == 0)
continue;
4199 for (
auto cid : ss3.CotIDs) {
4200 auto& ss = slc.
cots[cid - 1];
4201 if (ss.SS3ID != ss3.ID) {
4202 std::cout << fcnLabel <<
" ***** Error: 3S" << ss3.ID <<
" -> 2S" << cid
4203 <<
" but it thinks it belongs to 3S" << ss.SS3ID <<
"\n";
4215 if (slc.
showers.empty())
return;
4216 mf::LogVerbatim myprt(
"TC");
4217 myprt << fcnLabel <<
" 3D showers \n";
4218 for (
auto& ss3 : slc.
showers) {
4219 myprt << fcnLabel <<
" 3S" << ss3.ID <<
" 3V" << ss3.Vx3ID;
4220 myprt <<
" parentID " << ss3.ParentID;
4221 myprt <<
" ChgPos" << std::fixed;
4222 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
4223 myprt <<
" " << std::setprecision(0) << ss3.ChgPos[xyz];
4225 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
4226 myprt <<
" " << std::setprecision(2) << ss3.Dir[xyz];
4227 myprt <<
" posInPlane";
4228 std::vector<float> projInPlane(slc.
nPlanes);
4229 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
4230 CTP_t inCTP =
EncodeCTP(ss3.TPCID.Cryostat, ss3.TPCID.TPC, plane);
4231 auto tp =
MakeBareTP(detProp, slc, ss3.ChgPos, ss3.Dir, inCTP);
4232 myprt <<
" " <<
PrintPos(slc, tp.Pos);
4233 projInPlane[plane] = tp.Delta;
4235 myprt <<
" projInPlane";
4236 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
4237 myprt <<
" " << std::fixed << std::setprecision(2) << projInPlane[plane];
4239 for (
auto cid : ss3.CotIDs) {
4240 auto& ss = slc.
cots[cid - 1];
4241 myprt <<
"\n 2S" << ss.ID;
4242 auto& stj = slc.
tjs[ss.ShowerTjID - 1];
4243 myprt <<
" ST" << stj.ID;
4244 myprt <<
" " <<
PrintPos(slc, stj.Pts[stj.EndPt[0]].Pos) <<
" - "
4245 <<
PrintPos(slc, stj.Pts[stj.EndPt[1]].Pos);
4247 if (ss3.NeedsUpdate) myprt <<
" *** Needs update";
4257 if (slc.
cots.empty())
return;
4259 mf::LogVerbatim myprt(
"TC");
4262 bool printAllCTP = (inCTP == USHRT_MAX);
4264 unsigned short nlines = 0;
4265 for (
const auto& ss : slc.
cots) {
4266 if (!printAllCTP && ss.CTP != inCTP)
continue;
4267 if (!printKilledShowers && ss.ID == 0)
continue;
4271 myprt << someText <<
" Print2DShowers: Nothing to print";
4276 bool printHeader =
true;
4277 bool printExtras =
false;
4278 for (
unsigned short ict = 0; ict < slc.
cots.size(); ++ict) {
4279 const auto& ss = slc.
cots[ict];
4280 if (!printAllCTP && ss.CTP != inCTP)
continue;
4281 if (!printKilledShowers && ss.ID == 0)
continue;
4282 PrintShower(someText, slc, ss, printHeader, printExtras);
4283 printHeader =
false;
4286 for (
unsigned short ict = 0; ict < slc.
cots.size(); ++ict) {
4287 const auto& ss = slc.
cots[ict];
4288 if (!printAllCTP && ss.CTP != inCTP)
continue;
4289 if (!printKilledShowers && ss.ID == 0)
continue;
4290 myprt << someText << std::fixed;
4292 myprt << std::setw(5) << sid;
4294 for (
auto id : ss.TjIDs)
4295 myprt <<
" T" << id;
4299 for (
unsigned short ict = 0; ict < slc.
cots.size(); ++ict) {
4300 const auto& ss = slc.
cots[ict];
4301 if (!printAllCTP && ss.CTP != inCTP)
continue;
4302 if (!printKilledShowers && ss.ID == 0)
continue;
4303 myprt << someText << std::fixed;
4305 myprt << std::setw(5) << sid;
4306 myprt <<
" Envelope";
4307 for (
auto& vtx : ss.Envelope)
4308 myprt <<
" " << (int)vtx[0] <<
":" << (
int)(vtx[1] /
tcc.
unitsPerTick);
4312 for (
unsigned short ict = 0; ict < slc.
cots.size(); ++ict) {
4313 const auto& ss = slc.
cots[ict];
4314 if (!printAllCTP && ss.CTP != inCTP)
continue;
4315 if (!printKilledShowers && ss.ID == 0)
continue;
4316 myprt << someText << std::fixed;
4318 myprt << std::setw(5) << sid;
4320 for (
auto id : ss.NearTjIDs)
4321 myprt <<
" T" << id;
4325 myprt <<
"DontCluster";
4327 if (dc.TjIDs[0] > 0) myprt <<
" T" << dc.TjIDs[0] <<
"-T" << dc.TjIDs[1];
4329 myprt <<
"\nDontCluster";
4330 for (
unsigned short ict = 0; ict < slc.
cots.size(); ++ict) {
4331 const auto& iss = slc.
cots[ict];
4332 if (iss.ID == 0)
continue;
4333 for (
unsigned short jct = ict + 1; jct < slc.
cots.size(); ++jct) {
4334 const auto& jss = slc.
cots[jct];
4335 if (jss.ID == 0)
continue;
4336 if (
DontCluster(slc, iss.TjIDs, jss.TjIDs)) myprt <<
" 2S" << iss.ID <<
"-2S" << jss.ID;
4350 mf::LogVerbatim myprt(
"TC");
4354 <<
" ID CTP ParID ParFOM TruParID Energy nTjs dFOM AspRat stj vx0 __Pos0___ "
4355 "Chg(k) dRMS __Pos1___ Chg(k) dRMS __Pos2___ Chg(k) dRMS Angle SS3ID PFPID\n";
4358 myprt << someText << std::fixed;
4360 myprt << std::setw(5) << sid;
4361 myprt << std::setw(6) << ss.
CTP;
4364 myprt << std::setw(7) << sid;
4365 myprt << std::setw(7) << std::setprecision(2) << ss.
ParentFOM;
4367 myprt << std::setw(7) << (int)ss.
Energy;
4368 myprt << std::setw(5) << ss.
TjIDs.size();
4369 myprt << std::setw(6) << std::setprecision(2) << ss.
DirectionFOM;
4370 myprt << std::setw(7) << std::setprecision(2) << ss.
AspectRatio;
4373 myprt << std::setw(5) << tid;
4374 std::string vid =
"NA";
4376 myprt << std::setw(5) << vid;
4377 for (
auto& spt : stj.Pts) {
4378 myprt << std::setw(10) <<
PrintPos(slc, spt.Pos);
4379 myprt << std::setw(7) << std::fixed << std::setprecision(1) << spt.Chg / 1000;
4381 myprt << std::setw(5) << std::setprecision(1) << spt.DeltaRMS;
4383 myprt << std::setw(6) << std::setprecision(2) << stj.Pts[1].Ang;
4384 std::string sss =
"NA";
4386 myprt << std::setw(6) << sss;
4389 if (ss3.PFPIndex >= 0 && ss3.PFPIndex < slc.
pfps.size()) {
4391 myprt << std::setw(6) << pid;
4394 myprt << std::setw(6) <<
"NA";
4398 myprt << std::setw(6) <<
"NA";
4402 if (!printExtras)
return;
4405 myprt << someText << std::fixed;
4407 myprt << std::setw(5) << sid;
4409 for (
auto id : ss.
TjIDs)
4410 myprt <<
" T" << id;
4412 myprt << someText << std::fixed;
4414 myprt << std::setw(5) << sid;
4415 myprt <<
" Envelope";
4417 myprt <<
" " << (int)vtx[0] <<
":" << (
int)(vtx[1] /
tcc.
unitsPerTick);
4419 myprt << someText << std::fixed;
4421 myprt << std::setw(5) << sid;
4424 myprt <<
" T" << id;
bool AddTj(std::string inFcnLabel, TCSlice &slc, int tjID, ShowerStruct &ss, bool doUpdate, bool prt)
bool TransferTjHits(TCSlice &slc, bool prt)
short MCSMom(const TCSlice &slc, const std::vector< int > &tjIDs)
std::vector< Trajectory > tjs
vector of all trajectories in each plane
unsigned short FarEnd(const TCSlice &slc, const PFPStruct &pfp, const Point3_t &pos)
void MergeNearby2DShowers(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP, bool prt)
void ConfigureMVA(TCConfig &tcc, std::string fMVAShowerParentWeights)
then if[["$THISISATEST"==1]]
bool MakeVertexObsolete(std::string fcnLabel, TCSlice &slc, VtxStore &vx2, bool forceKill)
bool FindParent(detinfo::DetectorPropertiesData const &detProp, std::string inFcnLabel, TCSlice &slc, ShowerStruct3D &ss3, bool prt)
void ReverseShower(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
struct of temporary 2D vertices (end points)
std::vector< int > GetAssns(TCSlice &slc, std::string type1Name, int id, std::string type2Name)
std::vector< unsigned int > PutTrajHitsInVector(const Trajectory &tj, HitStatus_t hitRequest)
std::vector< ShowerStruct > cots
void MergeShowerChain(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP, bool prt)
std::vector< double > dEdxErr
double InShowerProbLong(double showerEnergy, double along)
bool ChkAssns(std::string inFcnLabel, TCSlice &slc)
std::vector< int > NearTjIDs
std::vector< ShowerStruct3D > showers
ShowerStruct3D CreateSS3(TCSlice &slc)
std::vector< Point2_t > Envelope
unsigned int Nplanes() const
Number of planes in this tpc.
Declaration of signal hit object.
void FindAlongTrans(Point3_t pos1, Vector3_t dir1, Point3_t pos2, Point2_t &alongTrans)
std::vector< std::vector< std::pair< unsigned int, unsigned int > > > wireHitRange
The data type to uniquely identify a Plane.
void PrintShowers(detinfo::DetectorPropertiesData const &detProp, std::string fcnLabel, TCSlice &slc)
Geometry information for a single TPC.
std::vector< unsigned int > Hits
std::vector< double > MIPEnergy
int GetCotID(TCSlice &slc, int ShowerTjID)
short MCSMom
Normalized RMS using ALL hits. Assume it is 50% to start.
void PrintShower(std::string someText, TCSlice &slc, const ShowerStruct &ss, bool printHeader, bool printExtras)
std::string PrintPos(const TCSlice &slc, const TrajPoint &tp)
CryostatID_t Cryostat
Index of cryostat.
bool WrongSplitTj(std::string inFcnLabel, TCSlice &slc, Trajectory &tj, unsigned short tjEnd, ShowerStruct &ss, bool prt)
PFPStruct CreatePFP(const TCSlice &slc)
void KillVerticesInShower(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
Point3_t PosAtEnd(const PFPStruct &pfp, unsigned short end)
void SaveAllCots(TCSlice &slc, const CTP_t &inCTP, std::string someText)
float PointTrajDOCA(const TCSlice &slc, unsigned int iht, TrajPoint const &tp)
double DeltaAngle(const Vector3_t v1, const Vector3_t v2)
bool FindShowers3D(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc)
double ShowerEnergy(const ShowerStruct3D &ss3)
bool dbgSlc
debug only in the user-defined slice? default is all slices
bool MakeBareTrajPoint(const TCSlice &slc, unsigned int fromHit, unsigned int toHit, TrajPoint &tp)
float ParentFOM(std::string inFcnLabel, TCSlice &slc, PFPStruct &pfp, unsigned short pend, ShowerStruct3D &ss3, bool prt)
std::vector< unsigned int > lastWire
the last wire with a hit
std::array< int, 2 > Vx3ID
bool IsShowerLike(TCSlice &slc, const std::vector< int > TjIDs)
std::vector< int > CotIDs
double InShowerProbTrans(double showerEnergy, double along, double trans)
std::vector< ShowerPoint > ShPts
void PrintPFPs(std::string someText, TCSlice &slc)
bool FindShowerStart(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, ShowerStruct3D &ss3, bool prt)
ShowerStruct CreateSS(TCSlice &slc, const std::vector< int > &tjl)
std::vector< T > SetIntersection(const std::vector< T > &set1, const std::vector< T > &set2)
bool AddLooseHits(TCSlice &slc, int cotID, bool prt)
bool DontCluster(TCSlice &slc, const std::vector< int > &tjlist1, const std::vector< int > &tjlist2)
void MergeTjList(std::vector< std::vector< int >> &tjList)
std::vector< float > showerTag
shower-like trajectory tagging + shower reconstruction
double InShowerProbParam(double showerEnergy, double along, double trans)
double ShowerParamTransRMS(double showerEnergy, double along)
void AddCloseTjsToList(TCSlice &slc, unsigned short itj, std::vector< int > list)
TrajPoint MakeBareTP(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, const Point3_t &pos, CTP_t inCTP)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Access the description of detector geometry.
void DefineEnvelope(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
void MergeSubShowersTj(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP, bool prt)
std::vector< DontClusterStruct > dontCluster
int NeutrinoPrimaryTjID(const TCSlice &slc, const Trajectory &tj)
void PrintAllTraj(detinfo::DetectorPropertiesData const &detProp, std::string someText, TCSlice &slc, unsigned short itj, unsigned short ipt, bool prtVtx)
std::array< float, 2 > Point2_t
float unitsPerTick
scale factor from Tick to WSE equivalent units
void DumpShowerPts(TCSlice &slc, int cotID)
Vector3_t PointDirection(const Point3_t p1, const Point3_t p2)
CTP_t CTP
Cryostat, TPC, Plane code.
float InShowerProb(TCSlice &slc, const ShowerStruct3D &ss3, const PFPStruct &pfp)
bool MergeShowerTjsAndStore(TCSlice &slc, unsigned short istj, unsigned short jstj, bool prt)
void TagShowerLike(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP)
std::vector< TrajPoint > Pts
Trajectory points.
TMVA::Reader * showerParentReader
float ChgFracNearPos(const TCSlice &slc, const Point2_t &pos, const std::vector< int > &tjIDs)
std::vector< float > showerParentVars
float ChgFracBetween(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, Point3_t pos1, Point3_t pos2)
auto end(FixedBins< T, C > const &) noexcept
void SaveTjInfo(TCSlice &slc, std::vector< std::vector< int >> &tjList, std::string stageName)
void FindNearbyTjs(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
std::vector< VtxStore > vtxs
2D vertices
std::array< unsigned short, 2 > EndPt
First and last point in the trajectory that has charge.
unsigned short PDGCode
shower-like or track-like {default is track-like}
bool PointInsideEnvelope(const Point2_t &Point, const std::vector< Point2_t > &Envelope)
void MergeOverlap(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP, bool prt)
void MakeTrajectoryObsolete(TCSlice &slc, unsigned int itj)
double PosSep2(const Point3_t &pos1, const Point3_t &pos2)
const geo::GeometryCore * geom
PlaneID_t Plane
Index of the plane within its TPC.
bool valsIncreasing(const SortEntry &c1, const SortEntry &c2)
bool SetMag(Vector3_t &v1, double mag)
Definition of data types for geometry description.
void ReverseTraj(TCSlice &slc, Trajectory &tj)
bool AddPFP(std::string inFcnLabel, TCSlice &slc, int pID, ShowerStruct3D &ss3, bool doUpdate, bool prt)
int ID
ID that is local to one slice.
std::vector< float > StartChgVec(TCSlice &slc, int cotID, bool prt)
std::vector< TCSlice > slices
std::array< unsigned short, 2 > VtxID
ID of 2D vertex.
bool AddTjsInsideEnvelope(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
double ConvertTicksToX(double ticks, int p, int t, int c) const
std::bitset< 16 > modes
number of points to find AveChg
std::vector< TCHit > slHits
std::vector< float > chargeCuts
auto begin(FixedBins< T, C > const &) noexcept
bool MergeShowersAndStore(std::string inFcnLabel, TCSlice &slc, int icotID, int jcotID, bool prt)
std::vector< double > EnergyErr
std::vector< double > MIPEnergyErr
double DotProd(const Vector3_t &v1, const Vector3_t &v2)
std::vector< Vtx3Store > vtx3s
3D vertices
bool RemoveTj(std::string inFcnLabel, TCSlice &slc, int TjID, ShowerStruct &ss, bool doUpdate, bool prt)
std::bitset< 128 > useAlg
Max hit separation for making junk trajectories. < 0 to turn off.
int MergeShowers(std::string inFcnLabel, TCSlice &slc, std::vector< int > ssIDs, bool prt)
void ShowerParams(double showerEnergy, double &shMaxAlong, double &along95)
std::string to_string(WindowPattern const &pattern)
std::bitset< 128 > AlgMod
Bit set if algorithm AlgBit_t modifed the trajectory.
std::vector< double > Energy
geo::PlaneID DecodeCTP(CTP_t CTP)
double PosSep(const Point3_t &pos1, const Point3_t &pos2)
std::vector< recob::Hit > const * allHits
bool valsDecreasing(const SortEntry &c1, const SortEntry &c2)
CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
std::pair< unsigned short, unsigned short > GetSliceIndex(std::string typeName, int uID)
std::array< double, 3 > Vector3_t
int ID
ID of the recob::Slice (not the sub-slice)
bool RemovePFP(std::string inFcnLabel, TCSlice &slc, PFPStruct &pfp, ShowerStruct3D &ss3, bool doUpdate, bool prt)
std::vector< T > SetDifference(const std::vector< T > &set1, const std::vector< T > &set2)
void MergeSubShowers(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP, bool prt)
void FindStartChg(std::string inFcnLabel, TCSlice &slc, int cotID, bool prt)
void Finish3DShowers(TCSlice &slc)
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
int SSID
ID of a 2D shower struct that this tj is in.
std::vector< PFPStruct > pfps
bool AnalyzeRotPos(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
float Match3DFOM(detinfo::DetectorPropertiesData const &detProp, std::string inFcnLabel, TCSlice &slc, ShowerStruct3D &ss3, bool prt)
unsigned short NumPtsWithCharge(const TCSlice &slc, const Trajectory &tj, bool includeDeadWires)
float ChgToMeV(float chg)
print OUTPUT<< EOF;< setup name="Default"version="1.0">< worldref="volWorld"/></setup ></gdml > EOF close(OUTPUT)
TPCID_t TPC
Index of the TPC within its cryostat.
bool UpdateShower(std::string inFcnLabel, TCSlice &slc, ShowerStruct &ss, bool prt)
std::vector< double > dEdx
bool TrajTrajDOCA(const TCSlice &slc, const Trajectory &tj1, const Trajectory &tj2, unsigned short &ipt1, unsigned short &ipt2, float &minSep)
Vector3_t DirAtEnd(const PFPStruct &pfp, unsigned short end)
bool empty(FixedBins< T, C > const &) noexcept
void Print2DShowers(std::string someText, TCSlice &slc, CTP_t inCTP, bool printKilledShowers)
bool CompleteIncompleteShower(std::string inFcnLabel, TCSlice &slc, ShowerStruct3D &ss3, bool prt)
bool SetParent(detinfo::DetectorPropertiesData const &detProp, std::string inFcnLabel, TCSlice &slc, PFPStruct &pfp, ShowerStruct3D &ss3, bool prt)
BEGIN_PROLOG could also be cout
CTP_t CTP
set to an invalid CTP
void MakeShowerObsolete(std::string inFcnLabel, TCSlice &slc, ShowerStruct3D &ss3, bool prt)
Encapsulate the construction of a single detector plane.
bool StoreShower(std::string inFcnLabel, TCSlice &slc, ShowerStruct3D &ss3)
bool Reconcile3D(std::string inFcnLabel, TCSlice &slc, bool parentSearchDone, bool prt)