Program Listing for File kpsreco_vertexana.cxx

Return to documentation for file (larflow/Ana/kpsreco_vertexana.cxx)

#include <iostream>
#include <string>

#include "TTree.h"

#include "larcv/core/DataFormat/IOManager.h"
#include "larcv/core/DataFormat/EventPGraph.h"
#include "DataFormat/storage_manager.h"
#include "DataFormat/larflow3dhit.h"
#include "LArUtil/LArProperties.h"
#include "LArUtil/Geometry.h"
#include "ublarcvapp/MCTools/LArbysMC.h"
#include "larflow/KeyPoints/PrepKeypointData.h"
#include "larflow/Reco/NuVertexCandidate.h"

int main( int nargs, char** argv )
{

  // keypoint reco analysis
  // output:
  //  1) ttree per event storing
  //     - mc event info
  //     - number of reco vertices near true neutrino vertex
  //     - number of reco vertices near true track keypoint
  //     - number of reco vertices that are false
  //  2) if wire-cell cosmic tagger info available, ttree per event storing
  //     - number of reco vertices near true neutrino vertex w/ wirecell mask
  //     - number of reco vertices near true track keypoint w/ wirecell mask
  //     - number of reco vertices that are false w/ wirecell mask

  // inputs
  // ------

  // 1) dlmerged file
  // 2) keypoint reco output

  std::string dlmerged_file = argv[1];
  std::string kpreco_file   = argv[2];

  // outputs
  // 1) ana tfile with ana ttree
  std::string outfilename   = argv[3];

  int ismc                  = std::atoi(argv[4]);

  // Load inputs
  larcv::IOManager iocv( larcv::IOManager::kREAD, "larcv", larcv::IOManager::kTickBackward );
  iocv.add_in_file( dlmerged_file );
  iocv.reverse_all_products();
  iocv.initialize();

  larlite::storage_manager ioll( larlite::storage_manager::kREAD );
  ioll.add_in_filename( dlmerged_file );
  ioll.set_data_to_read( larlite::data::kMCTruth,  "generator" );
  ioll.set_data_to_read( larlite::data::kMCTrack,  "mcreco" );
  ioll.set_data_to_read( larlite::data::kMCShower, "mcreco" );
  ioll.open();

  TFile kpreco_tfile(kpreco_file.c_str(),"open");
  TTree* kpreco_ttree = (TTree*)kpreco_tfile.Get("KPSRecoManagerTree");
  std::vector<larflow::reco::NuVertexCandidate>* ev_kpreco = 0;
  std::vector<larflow::reco::NuVertexCandidate>* ev_kpreco_fitted = 0;
  kpreco_ttree->SetBranchAddress( "nuvetoed_v", &ev_kpreco );
  kpreco_ttree->SetBranchAddress( "nufitted_v", &ev_kpreco_fitted );

  // load outputs
  TFile* out = new TFile(outfilename.c_str(),"new");

  // define output trees

  // per-event analysis tree
  TTree* ev_ana = new TTree("nuvertexana_event","Nu Vertex Reco Ana Event tree");

  int run,subrun,event;

  int n_reco;               //< total number of candidates per event
  int n_near_true_vtx;      //< number near true vertex (within 5 cm)
  int n_false;              //< number of false vertices

  int n_reco_wct;           //< total vertices if we exclude those on the WC tagged pixels
  int n_near_true_vtx_wct;  //< num near true vertex (within 5 cm)
  int n_false_wct;          //< number false after wire cell filter

  int n_reco_dl;            //< number of DL vertices
  int n_near_true_vtx_dl;  //< num dl vertices near truth vertex
  int n_false_dl;           //< number of false dl vertices

  float truth_vtx_qsum[3] = { 0., 0., 0. };  // truth of charge near the vertex
  float min_dist_to_vtx     = 0.;            // min distance to closest reco vtx
  float min_dist_to_vtx_wct = 0.;            // min distance to closest reco vtx not on tagged pixel
  float min_dist_to_vtx_dl  = 0.;            // min distance to closest reco DL vtx
  float min_dist_to_vtx_fit = 0.;            // min distance to closest reco vtx after fitting prongs

  float difftrue_after_fit_cm   = 0.;        // relative distance to true vtx before and after fit
  float diffreco_after_fit_cm   = 0.;        // diff of vertex pos before and after fit

  ev_ana->Branch("run",&run,"run/I");
  ev_ana->Branch("subrun",&subrun,"subrun/I");
  ev_ana->Branch("event",&event,"event/I");

  ev_ana->Branch("n_reco",&n_reco,"n_reco/I");
  ev_ana->Branch("n_near_true_vtx",&n_near_true_vtx,"n_near_true_vtx/I");
  ev_ana->Branch("n_false",&n_false,"n_false/I");

  ev_ana->Branch("n_reco_wct",&n_reco_wct,"n_reco_wct/I");
  ev_ana->Branch("n_near_true_vtx_wct",&n_near_true_vtx_wct,"n_near_true_vtx_wct/I");
  ev_ana->Branch("n_false_wct",&n_false_wct,"n_false_wct/I");

  ev_ana->Branch("n_reco_dl",&n_reco_dl,"n_reco_dl/I");
  ev_ana->Branch("n_near_true_vtx_dl",&n_near_true_vtx_dl,"n_near_true_vtx_dl/I");
  ev_ana->Branch("n_false_dl",&n_false_dl,"n_false_dl/I");

  ev_ana->Branch("min_dist_to_vtx",     &min_dist_to_vtx,     "min_dist_to_vtx/F" );
  ev_ana->Branch("min_dist_to_vtx_dl",  &min_dist_to_vtx_dl,  "min_dist_to_vtx_dl/F" );
  ev_ana->Branch("min_dist_to_vtx_wct", &min_dist_to_vtx_wct, "min_dist_to_vtx_wct/F" );
  ev_ana->Branch("min_dist_to_vtx_fit", &min_dist_to_vtx_fit, "min_dist_to_vtx_fit/F" );
  ev_ana->Branch("true_vtx_qsum",truth_vtx_qsum, "true_vtx_qsum[3]/F" );

  ev_ana->Branch("difftrue_after_fit_cm", &difftrue_after_fit_cm, "difftrue_after_fit_cm/F" );
  ev_ana->Branch("diffreco_after_fit_cm", &diffreco_after_fit_cm, "diffreco_after_fit_cm/F" );

  // per reco vertex analysis tree
  TTree* kp_ana = new TTree("vertexana_recovertex","Ana per reco vertex");
  // int   nshower;
  // int   ntrack;
  // int   nshower_true;
  // int   ntrack_true;
  float pos[3];
  float score;
  float dist_to_vertex;
  kp_ana->Branch("pos",pos,"pos[3]/F");
  kp_ana->Branch("score",&score,"score/F");
  kp_ana->Branch("dist_to_vertex",&dist_to_vertex,"dist_to_vertex/F");


  const float cut_off_dist = 10.0; // cm
  const float cut_off_distsq = cut_off_dist*cut_off_dist;

  // Keypoint Truth Data Maker
  //larflow::keypoints::PrepKeypointData kpdata; //truth key points
  ublarcvapp::mctools::LArbysMC lmc;
  lmc.bindAnaVariables( ev_ana );
  kp_ana->Branch("nlepton_35mev",&lmc._nlepton_35mev,"nlepton_35mev/I");
  kp_ana->Branch("nproton_60mev",&lmc._nproton_60mev,"nproton_60mev/I");
  kp_ana->Branch("nmeson_35mev",&lmc._nmeson_35mev,"nmeson_35mev/I");
  kp_ana->Branch("nshower",&lmc._nshower,"nshower/I");

  int nentries = iocv.get_n_entries();
  for (int ientry=0; ientry<nentries; ientry++) {

    // load trees
    iocv.read_entry(ientry);
    ioll.go_to(ientry);
    kpreco_ttree->GetEntry(ientry);

    if ( ev_kpreco->size()!=ev_kpreco_fitted->size() ) {
      throw std::runtime_error("Differnet number of prefit and postfit vertices!");
    }

    // Get neutrino interaction truth
    float true_vtx[3] = { 0 };
    if ( ismc ) {
      lmc.process( ioll );

      // true vertex after space charge correction
      true_vtx[0] = lmc._vtx_sce_x;
      true_vtx[1] = lmc._vtx_sce_y;
      true_vtx[2] = lmc._vtx_sce_z;
    }

    // truth keypoints
    //kpdata.process( iocv, ioll );

    // wirecell cosmic pixel image
    larcv::EventImage2D* ev_thrumu =
      (larcv::EventImage2D*)iocv.get_data(larcv::kProductImage2D,"thrumu");
    auto const& thrumu_v = ev_thrumu->Image2DArray();

    // ADC images
    larcv::EventImage2D* ev_adc =
      (larcv::EventImage2D*)iocv.get_data(larcv::kProductImage2D,"wire");
    auto const& adc_v = ev_adc->Image2DArray();

    // DL Vertex
    larcv::EventPGraph* ev_pgraph =
      (larcv::EventPGraph*)iocv.get_data(larcv::kProductPGraph,"test");

    std::cout << "[ENTRY " << ientry << "]" << std::endl;
    //std::cout << "  number of truth keypoints: " << kpdata.getKPdata().size() << std::endl;
    std::cout << "  number of reco keypoints: " << ev_kpreco->size() << std::endl;
    std::cout << "  number of Wirecell images: " << thrumu_v.size() << std::endl;
    std::cout << "  number of DL reco vertices: " << ev_pgraph->PGraphArray().size() << std::endl;
    std::cout << "  true neutrino vertex: (" << true_vtx[0] << "," << true_vtx[1] << "," << true_vtx[2] << ")" << std::endl;
    if ( ismc ) {
      lmc.printInteractionInfo();
      //kpdata.printKeypoints();
    }

    // number of reco vertices
    n_reco = (int)ev_kpreco->size();

    // KP Reco loop
    n_near_true_vtx = 0;
    n_false = 0;

    n_reco_wct = 0;
    n_near_true_vtx_wct = 0;
    n_false_wct = 0;

    n_reco_dl = (int)ev_pgraph->PGraphArray().size();
    n_near_true_vtx_dl = 0;
    n_false_dl = 0;

    // characterize vertex
    min_dist_to_vtx     = 1110;
    min_dist_to_vtx_wct = 1110;
    min_dist_to_vtx_dl  = 1110;
    min_dist_to_vtx_fit = 1110;

    // get vertex activity
    // sum charge on the three planes
    if ( ismc ) {
      for (int p=0; p<3; p++) truth_vtx_qsum[p] = 0.0;
      if ( lmc._vtx_tick>adc_v[0].meta().min_y() && lmc._vtx_tick<adc_v[0].meta().max_y() ) {
        int row = adc_v[0].meta().row( lmc._vtx_tick );

        for (int p=0; p<3; p++ ) {

          if ( lmc._vtx_wire[p]>=adc_v[p].meta().min_x() && lmc._vtx_wire[p]<(int)adc_v[p].meta().max_x() ) {
            int col = adc_v[p].meta().col( lmc._vtx_wire[p] );

            for (int dr=-3; dr<=3; dr++ ) {
              int r=row+dr;
              if ( r<0 || r>=(int)adc_v[p].meta().rows() ) continue;
              for (int dc=-3; dc<=3; dc++) {
                int c = col+dc;
                if (c<0 || c>=(int)adc_v[p].meta().cols() ) continue;
                if ( adc_v[p].pixel(r,c)>10.0 )
                  truth_vtx_qsum[p] += adc_v[p].pixel(r,c);
              }//end of col loop
            }//end of row loop
          }//end of if valid wire
        }//end of plane loop
      }//end of if valid tick
    }

    if ( ismc ) {
      // get dl vertex info
      for ( auto const& pgraph : ev_pgraph->PGraphArray() ) {
        for ( auto const& roi : pgraph.ParticleArray() ) {
          float dist = 0.;
          dist += ( roi.X()-true_vtx[0] )*( roi.X()-true_vtx[0] );
          dist += ( roi.Y()-true_vtx[1] )*( roi.Y()-true_vtx[1] );
          dist += ( roi.Z()-true_vtx[2] )*( roi.Z()-true_vtx[2] );
          dist = sqrt(dist);
          std::cout << "dl vtx: (" << roi.X() << "," << roi.Y() << "," << roi.Z() << ") dist2vtx=" << dist << " cm" << std::endl;
          if ( min_dist_to_vtx_dl>dist ) {
            min_dist_to_vtx_dl = dist;
          }
          if ( dist<5.0 )
            n_near_true_vtx_dl++;
        }
      }
    }

    // analysis for reco keypoints
    int ivtx = -1;
    for ( auto const& kpc : *ev_kpreco ) {
      ivtx++;

      for (int i=0; i<3; i++)
        pos[i] = kpc.pos[i];

      score = kpc.score;

      auto const& kpc_fit = ev_kpreco_fitted->at(ivtx);


      // determine if on Wirecell-tagged cosmic
      // requirement: be on tagged pixel for 2/3 planes
      bool iscosmic = false;

      float tick = 3200 + kpc.pos[0]/larutil::LArProperties::GetME()->DriftVelocity()/0.5;
      if ( tick<=thrumu_v[0].meta().min_y() || tick>=thrumu_v[0].meta().max_y() ) {
        iscosmic = true;
      }
      else {
        int row = thrumu_v[0].meta().row( tick );
        int nplanes_on_wctpixel = 0;
        for ( auto const& img : thrumu_v ) {
          // out of image?  we remove it implicitly by adding to counter
          std::vector<double> dpos = { (double)kpc.pos[0],
                                       (double)kpc.pos[1],
                                       (double)kpc.pos[2] };
          int nearestwire = larutil::Geometry::GetME()->NearestWire( dpos, img.meta().plane() );
          int col = img.meta().col((float)nearestwire);

          bool onpixel = false;
          for (int dr=-1; dr<=1; dr++) {
            int r = row+dr;
            if ( r<0 || r>=(int)img.meta().rows() ) continue;
            for (int dc=-1; dc<=1; dc++) {
              int c = col+dc;
              if ( c<0 || c>=(int)img.meta().cols() ) continue;
              if ( img.pixel(r,c)>10.0 ) onpixel = true;
              if ( onpixel ) break;
            }
            if ( onpixel ) break;
          }

          if ( onpixel ) nplanes_on_wctpixel++;
        }
        if ( nplanes_on_wctpixel>=3 ) iscosmic = true;
      }

      // dist to vtx
      dist_to_vertex = 0;
      float dist_to_fitvtx = 0.;
      if ( ismc ) {
        for (int i=0; i<3; i++) {
          dist_to_vertex += (kpc.pos[i]-true_vtx[i])*(kpc.pos[i]-true_vtx[i]);
          dist_to_fitvtx += (kpc_fit.pos[i]-true_vtx[i])*(kpc_fit.pos[i]-true_vtx[i]);
        }
        dist_to_vertex = sqrt(dist_to_vertex);
        dist_to_fitvtx = sqrt(dist_to_fitvtx);


        if ( dist_to_vertex < min_dist_to_vtx )
          min_dist_to_vtx = dist_to_vertex;

        if ( dist_to_fitvtx < min_dist_to_vtx_fit )
          min_dist_to_vtx_fit = dist_to_fitvtx;

        if ( !iscosmic && dist_to_vertex<min_dist_to_vtx_wct ) {
          min_dist_to_vtx_wct = dist_to_vertex;
        }

        if ( dist_to_vertex>5.0 )
          n_false++;
        else
          n_near_true_vtx++;

        if ( !iscosmic ) {
          if ( dist_to_vertex>5.0 )
            n_false_wct++;
          else
            n_near_true_vtx_wct++;
        }
      }
      else {
        dist_to_vertex = 0;
      }
      std::cout << "RecoVtx[" << ivtx << "] score=" << score << " dist-to-vertex=" << dist_to_vertex  << std::endl;

      // compare pre and post fit


      kp_ana->Fill();

    }//end of reco vertex loop



    // for ( auto const& kpd : kpdata.getKPdata() ) {
    //   // for each truth keypoint, we save max triplet within certain distance
    //   max_score_dist = 1.0e9;
    //   max_score = -1.0;
    //   float dist = 0.;
    //   for ( auto const& hit : *ev_lmhit ) {
    //     dist = 0.;
    //     for (int i=0; i<3; i++) {
    //       dist += (hit[i]-kpd.keypt[i])*(hit[i]-kpd.keypt[i]);
    //       vtx_sce[i] = kpd.keypt[i];
    //     }
    //     if ( dist<cut_off_distsq ) {
    //       if ( hit[13]>max_score ) {
    //         max_score = hit[13];
    //         max_score_dist = sqrt(dist);
    //       }
    //     }
    //   }

    ev_ana->Fill();


  }//end of event loop

  out->Write();

  return 0;
}