.. _program_listing_file_larflow_Reco_ShowerLikelihoodBuilder.cxx: Program Listing for File ShowerLikelihoodBuilder.cxx ==================================================== |exhale_lsh| :ref:`Return to documentation for file ` (``larflow/Reco/ShowerLikelihoodBuilder.cxx``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "ShowerLikelihoodBuilder.h" #include "larcv/core/DataFormat/DataFormatTypes.h" #include "larcv/core/DataFormat/EventImage2D.h" #include "DataFormat/larflow3dhit.h" #include "DataFormat/mcshower.h" #include "LArUtil/SpaceChargeMicroBooNE.h" #include "ublarcvapp/MCTools/MCPixelPGraph.h" #include "cluster_functions.h" namespace larflow { namespace reco { ShowerLikelihoodBuilder::ShowerLikelihoodBuilder() { _hll = new TH2F("lfshower_ll","",2000, -10, 190, 1000, 0, 100 ); _hll_weighted = new TH2F("lfshower_ll_weighted","",2000, -10, 190, 1000, 0, 100 ); _psce = new larutil::SpaceChargeMicroBooNE(); } ShowerLikelihoodBuilder::~ShowerLikelihoodBuilder() { // if ( _hll ) delete _hll; // _hll = nullptr; } void ShowerLikelihoodBuilder::process( larcv::IOManager& iolcv, larlite::storage_manager& ioll ) { // get input data larcv::EventImage2D* ev_adc = (larcv::EventImage2D*)iolcv.get_data( larcv::kProductImage2D, "wiremc" ); larcv::EventImage2D* ev_seg = (larcv::EventImage2D*)iolcv.get_data( larcv::kProductImage2D, "segment" ); larcv::EventImage2D* ev_trueflow = (larcv::EventImage2D*)iolcv.get_data( larcv::kProductImage2D, "larflow" ); larlite::event_mcshower* ev_mcshower = (larlite::event_mcshower*)ioll.get_data( larlite::data::kMCShower, "mcreco" ); std::vector masked_v; std::vector badch_v; for ( size_t p=0; p<3; p++ ) { auto const& adc = ev_adc->Image2DArray()[p]; auto const& seg = ev_seg->Image2DArray()[p]; // image with shower pixels only larcv::Image2D masked(adc.meta()); masked.paint(0.0); // dummy badch, where every channel is a dummy channel larcv::Image2D badch(adc.meta()); badch.paint(0.0); // find shower pixels for ( size_t r=0; r0) badch.set_pixel(r,c,50.0); if ( pid !=larcv::kROIEminus && pid!=larcv::kROIGamma ) continue; // copy pixel if ( adc.pixel(r,c)>10 ) masked.set_pixel( r, c, adc.pixel(r,c) ); else masked.set_pixel( r, c, 15.0 ); } } masked_v.emplace_back( std::move(masked) ); badch_v.emplace_back( std::move(badch) ); } // images made, now we make the triplets tripletalgo.process( masked_v, badch_v, 1.0, true ); tripletalgo.make_truth_vector( ev_trueflow->Image2DArray() ); // save the true triplets as larflow3dhits std::vector truehit_v; for ( size_t i=0; i nodes_v = mcpg.getNeutrinoParticles(); // we loop over the different MC showers // we try to associate a truehit cluster to the mc shower object struct ShowerInfo_t { int idx; int pid; int origin; int priority; int matched_cluster; std::vector shower_dir; std::vector shower_dir_sce; std::vector shower_vtx; std::vector shower_vtx_sce; bool operator<(const ShowerInfo_t& rhs ) { if ( priority shower_info_v; for ( size_t idx=0; idxsize(); idx++ ) { auto const& mcsh = ev_mcshower->at( idx ); ShowerInfo_t info; info.idx = idx; info.pid = mcsh.PdgCode(); info.origin = mcsh.Origin(); if ( info.origin==1 && abs(info.pid)==11 ) info.priority = 0; else if ( info.origin==1 && abs(info.pid)==22 ) info.priority = 1; else if ( info.origin==1 ) info.priority = 2; else if ( info.origin==2 && abs(info.pid)==11 ) info.priority = 3; else info.priority = 4; info.shower_dir.resize(3,0); info.shower_vtx.resize(3,0); info.shower_dir_sce.resize(3,0); info.shower_vtx_sce.resize(3,0); auto const& detprofdir = mcsh.DetProfile().Momentum().Vect(); for (int i=0; i<3; i++) { info.shower_dir[i] = detprofdir[i]/detprofdir.Mag(); info.shower_vtx[i] = mcsh.DetProfile().Position()[i]; } float dirnorm = 0.; for (int v=0; v<3; v++) dirnorm += info.shower_dir[v]*info.shower_dir[v]; dirnorm = sqrt(dirnorm); for (int v=0; v<3; v++) info.shower_dir[v] /= dirnorm; // adjust shower dir due to SCE float cos_sce = 1.0; if ( abs(info.pid)==11 ) { // SCE corrected direction std::vector shower_end(3,0); for (int p=0; p<3; p++ ) shower_end[p] = info.shower_vtx[p] + 3.0*info.shower_dir[p]; std::vector offset = _psce->GetPosOffsets( info.shower_vtx[0], info.shower_vtx[1], info.shower_vtx[2] ); info.shower_vtx_sce = { info.shower_vtx[0] - (float)offset[0] + (float)0.6, info.shower_vtx[1] + (float)offset[1], info.shower_vtx[2] + (float)offset[2] }; offset = _psce->GetPosOffsets( shower_end[0], shower_end[1], shower_end[2] ); std::vector shower_end_sce = { shower_end[0] - (float)offset[0] + (float)0.6, shower_end[1] + (float)offset[1], shower_end[2] + (float)offset[2] }; float scenorm = 0.; for (int i=0; i<3; i++ ) { info.shower_dir_sce[i] = shower_end_sce[i]-info.shower_vtx_sce[i]; scenorm += info.shower_dir_sce[i]*info.shower_dir_sce[i]; cos_sce += info.shower_dir[i]*info.shower_dir_sce[i]; } scenorm = sqrt(scenorm); for (int i=0; i<3; i++ ) info.shower_dir_sce[i] /= scenorm; cos_sce /= scenorm; } else { for (int i=0; i<3; i++ ) { info.shower_dir_sce[i] = info.shower_dir[i]; info.shower_vtx_sce[i] = info.shower_vtx[i]; } } std::cout << "[ShowerLikelihoodBuilder] true shower " << std::endl; std::cout << " pid=" << info.pid << std::endl; std::cout << " dir-truth=(" << info.shower_dir[0] << "," << info.shower_dir[1] << "," << info.shower_dir[2] << ")" << std::endl; std::cout << " dir-sce=(" << info.shower_dir_sce[0] << "," << info.shower_dir_sce[1] << "," << info.shower_dir_sce[2] << ")" << std::endl; std::cout << " cos(truth*sce)=" << cos_sce << std::endl; std::cout << " vertex-truth=(" << info.shower_vtx[0] << "," << info.shower_vtx[1] << "," << info.shower_vtx[2] << ")" << std::endl; std::cout << " vertex-sce=(" << info.shower_vtx_sce[0] << "," << info.shower_vtx_sce[1] << "," << info.shower_vtx_sce[2] << ")" << std::endl; shower_info_v.push_back( info ); } std::sort( shower_info_v.begin(), shower_info_v.end() ); std::cout << "[ShowerLikelihoodBuilder] saved " << shower_info_v.size() << " showers" << std::endl; std::vector claimed_cluster_v( cluster_v.size(), 0 ); std::vector cluster_match_v( shower_info_v.size(), -1 ); int iidx = 0; for ( auto& info : shower_info_v ) { std::cout << "[" << iidx << "] pid=" << info.pid << " origin=" << info.origin << " vtx=(" << info.shower_vtx_sce[0] << "," << info.shower_vtx_sce[1] << "," << info.shower_vtx_sce[2] << ")" << std::endl; int match_cluster_idx = _find_closest_cluster( claimed_cluster_v, info.shower_vtx_sce, info.shower_dir_sce ); shower_info_v[iidx].matched_cluster = match_cluster_idx; std::cout << " matched cluster index: " << match_cluster_idx << std::endl; iidx++; } /* // cluster hits into cluster_t objects, using dbscan _analyze_clusters( truehit_v, shower_dir_sce, shower_vtx_sce ); */ std::vector< larlite::larflow3dhit > clustered_truehits_v; for ( auto& cluster : cluster_v ) { for ( auto& hitidx : cluster.hitidx_v ) { clustered_truehits_v.push_back( truehit_v[hitidx] ); } } // fill profile histogram // break into clusters // truth ID the trunk cluster // save vars for the trunk verus non-trunk clutsters // // _fillProfileHist( truehit_v, shower_dir_sce, shower_vtx_sce ); // mcpg.printGraph(); // save the larflow hits larlite::event_larflow3dhit* evout = (larlite::event_larflow3dhit*)ioll.get_data(larlite::data::kLArFlow3DHit, "trueshowerhits" ); for (auto& hit : clustered_truehits_v ) evout->emplace_back( std::move(hit) ); // save the shower object we are basing the info on larlite::event_mcshower* mcshowerout = (larlite::event_mcshower*)ioll.get_data(larlite::data::kMCShower, "truthshower" ); for ( auto& info : shower_info_v ) { mcshowerout->push_back( ev_mcshower->at( info.idx ) ); } // save the pca's of the clusters larlite::event_pcaxis* evout_pcaxis = (larlite::event_pcaxis*)ioll.get_data(larlite::data::kPCAxis, "truthshower"); for ( size_t cidx=0; cidxpush_back( llpca ); } // saved masked shower image larcv::EventImage2D* evimgout = (larcv::EventImage2D*)iolcv.get_data(larcv::kProductImage2D, "trueshoweradc" ); evimgout->Emplace( std::move(masked_v) ); } void ShowerLikelihoodBuilder::_fillProfileHist( const std::vector& truehit_v, std::vector& shower_dir, std::vector& shower_vtx ) { // get distance of point from pca-axis // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html std::cout << "Fill hits for shower[ " << "dir=(" << shower_dir[0] << "," << shower_dir[1] << "," << shower_dir[2] << ") " << "vtx=(" << shower_vtx[0] << "," << shower_vtx[1] << "," << shower_vtx[2] << ") " << "] with nhits=" << truehit_v.size() << std::endl; std::vector shower_end(3); std::vector d3(3); float len3 = 1.0; for (int i=0; i<3; i++ ) { shower_end[i] = shower_vtx[i] + shower_dir[i]; d3[i] = shower_dir[i]; } for ( auto const& hit : truehit_v ) { std::vector pt = { hit[0], hit[1], hit[2] }; std::vector d1(3); std::vector d2(3); float len1 = 0.; for (int i=0; i<3; i++ ) { d1[i] = pt[i] - shower_vtx[i]; d2[i] = pt[i] - shower_end[i]; len1 += d1[i]*d1[i]; } len1 = sqrt(len1); // cross-product std::vector d1xd2(3); d1xd2[0] = d1[1]*d2[2] - d1[2]*d2[1]; d1xd2[1] = -d1[0]*d2[2] + d1[2]*d2[0]; d1xd2[2] = d1[0]*d2[1] - d1[1]*d2[0]; float len1x2 = 0.; for ( int i=0; i<3; i++ ) { len1x2 += d1xd2[i]*d1xd2[i]; } len1x2 = sqrt(len1x2); float rad = len1x2/len3; // distance of point from PCA-axis float proj = 0.; for ( int i=0; i<3; i++ ) proj += shower_dir[i]*d1[i]; // std::cout << " hit: (" << pt[0] << "," << pt[1] << "," << pt[2] << ") " // << " dist=" << len1 // << " proj=" << proj // << " rad=" << rad // << std::endl; float w=1.; if ( rad>0 ) w = 1.0/rad; _hll_weighted->Fill( proj, rad, w ); _hll->Fill( proj, rad ); } } void ShowerLikelihoodBuilder::_make_truehit_clusters( std::vector< larlite::larflow3dhit >& truehit_v ) { cluster_v.clear(); float maxdist = 1.0; int minsize = 50; int maxkd = 5; cluster_larflow3dhits( truehit_v, cluster_v, maxdist, minsize, maxkd ); for ( auto& cluster : cluster_v ) cluster_pca( cluster ); } int ShowerLikelihoodBuilder::_find_closest_cluster( std::vector& claimed_cluster_v, std::vector& shower_vtx, std::vector& shower_dir ) { // we define the trunk of the cluster as the one closest to the shower start float min_dist2vtx = 1.0e9; std::vector trunk_endpt(3,0); int best_matched_cluster = -1; for ( size_t idx=0; idx trunk_endpt(3,0); for ( size_t idx=0; idx impactpt(3,0); for (int i=0; i<3; i++) { impactpt[i] = trunk_endpt[i] + proj_trunk*near_vtx.pca_axis_v[0][i]; } // [1: distance] // we use distance between impact point on trunk and endpoints float enddist[2] = { 0, 0 }; for (int e=0; e<2; e++) { for(int i=0; i<3; i++) { enddist[e] += (impactpt[i]-clust.pca_ends_v[e][i])*(impactpt[i]-clust.pca_ends_v[e][i]); } enddist[e] = sqrt(enddist[e]); } float clust_dist = (enddist[0]& ray_start, const std::vector& ray_dir, const std::vector& pt, float& radial_dist, float& projection ) { std::vector d1(3); std::vector d2(3); float len3 = 0.; std::vector end(3,0); for (int i=0; i<3; i++) { end[i] = ray_start[i] + ray_dir[i]; len3 += ray_dir[i]*ray_dir[i]; } len3 = sqrt(len3); float len1 = 0.; for (int i=0; i<3; i++ ) { d1[i] = pt[i] - ray_start[i]; d2[i] = pt[i] - end[i]; len1 += d1[i]*d1[i]; } len1 = sqrt(len1); // cross-product std::vector d1xd2(3); d1xd2[0] = d1[1]*d2[2] - d1[2]*d2[1]; d1xd2[1] = -d1[0]*d2[2] + d1[2]*d2[0]; d1xd2[2] = d1[0]*d2[1] - d1[1]*d2[0]; float len1x2 = 0.; for ( int i=0; i<3; i++ ) { len1x2 += d1xd2[i]*d1xd2[i]; } len1x2 = sqrt(len1x2); radial_dist = len1x2/len3; // distance of point from PCA-axis projection = 0.; for ( int i=0; i<3; i++ ) projection += ray_dir[i]*d1[i]/len3; } void ShowerLikelihoodBuilder::_impactdist( const std::vector& l_start, const std::vector& l_dir, const std::vector& m_start, const std::vector& m_dir, float& impact_dist, float& proj_l, float& proj_m ) { impact_dist = -1.0; proj_l = 0.; proj_m = 0.; // L = a + bs where a,b in R3, s in R // M = c + dt where c,d in R3, t in R float b2 = 0.; // l dir squared float d2 = 0.; // m dir squred float bd = 0.; // innerproduct l and m std::vector e(3,0.); // line segment of start points m->l float be = 0.; // inner product l_dir and e float de = 0.; // inner product m_dir and e for (int i=0; i<3; i++) { b2 += l_dir[i]*l_dir[i]; d2 += m_dir[i]*m_dir[i]; bd += l_dir[i]*m_dir[i]; e[i] = l_start[i]-m_start[i]; be += e[i]*l_dir[i]; de += e[i]*m_dir[i]; } float A = -1.0*(b2*d2 - bd*bd); if (A==0) { return; } // parallel lines float s = (-1.0*b2*de + be*bd)/A; float t = (d2*be - be*bd)/A; float D = 0.; // distance for (int i=0; i<3; i++ ) { float dd = e[i] + l_dir[i]*t - m_dir[i]*s; D += dd*dd; } D = sqrt(D); impact_dist = D; proj_l = s; proj_m = t; } } }