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)