#include "filval/filval.hpp"
#include "filval/root/filval.hpp"

#include<cmath>

#include "TrackingNtuple.h"

using namespace std;
using namespace fv;
using namespace fv::root;

typedef TreeDataSet<TrackingNtuple> TrackingDataSet;

//#^#=========================================================================
//==============PIXEL REC HIT=================================================
//============================================================================
struct PixRecHit {
    unsigned int   idx;
    unsigned short det;
    unsigned short lay;
    unsigned short ladder_blade;
    unsigned int   detId;
    unsigned short simType;
    float          x;
    float          y;
    float          z;
    float          xx;
    float          xy;
    float          yy;
    float          yz;
    float          zz;
    float          zx;
    float          radL;
    float          bbxi;
    vector<int>    trkIdx;
    vector<int>    seeIdx;
    vector<int>    simHitIdx;
    vector<float>  chargeFraction;

    float phi() const {
        return atan2(x, y);
    }
};

Value<vector<PixRecHit>>*
register_pixrec_hits(TrackingDataSet &tds){
    auto builder = func<std::vector<PixRecHit>(vector<unsigned short>,
                                               vector<unsigned short>,
                                               vector<unsigned short>,
                                               vector<unsigned int>,
                                               vector<unsigned short>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<float>,
                                               vector<vector<int>>,
                                               vector<vector<int>>,
                                               vector<vector<int>>,
                                               vector<vector<float>>)>("build_pixrec_hits",
        FUNC(([](const vector<unsigned short>& det,
                 const vector<unsigned short>& lay,
                 const vector<unsigned short>& ladder_blade,
                 const vector<unsigned int>&   detId,
                 const vector<unsigned short>& simType,
                 const vector<float>& x,
                 const vector<float>& y,
                 const vector<float>& z,
                 const vector<float>& xx,
                 const vector<float>& xy,
                 const vector<float>& yy,
                 const vector<float>& yz,
                 const vector<float>& zz,
                 const vector<float>& zx,
                 const vector<float>& radL,
                 const vector<float>& bbxi,
                 const vector<vector<int>>& trkIdx,
                 const vector<vector<int>>& seeIdx,
                 const vector<vector<int>>& simHitIdx,
                 const vector<vector<float>>& chargeFraction){
            std::vector<PixRecHit> pixrec_hits;
            for(unsigned int i=0; i<det.size(); i++)
                pixrec_hits.push_back({i,
                                       det[i],
                                       lay[i],
                                       ladder_blade[i],
                                       detId[i],
                                       simType[i],
                                       x[i],
                                       y[i],
                                       z[i],
                                       xx[i],
                                       xy[i],
                                       yy[i],
                                       yz[i],
                                       zz[i],
                                       zx[i],
                                       radL[i],
                                       bbxi[i],
                                       trkIdx[i],
                                       seeIdx[i],
                                       simHitIdx[i],
                                       chargeFraction[i]
                                       });
            return pixrec_hits;
        })));


    return tup_apply(builder,
        fv::tuple(tds.track_branch_obj<vector<unsigned short>>("pix_det"),
                  tds.track_branch_obj<vector<unsigned short>>("pix_lay"),
                  tds.track_branch_obj<vector<unsigned short>>("pix_ladder_blade"),
                  tds.track_branch_obj<vector<unsigned int>>("pix_detId"),
                  tds.track_branch_obj<vector<unsigned short>>("pix_simType"),
                  tds.track_branch_obj<vector<float>>("pix_x"),
                  tds.track_branch_obj<vector<float>>("pix_y"),
                  tds.track_branch_obj<vector<float>>("pix_z"),
                  tds.track_branch_obj<vector<float>>("pix_xx"),
                  tds.track_branch_obj<vector<float>>("pix_xy"),
                  tds.track_branch_obj<vector<float>>("pix_yy"),
                  tds.track_branch_obj<vector<float>>("pix_yz"),
                  tds.track_branch_obj<vector<float>>("pix_zz"),
                  tds.track_branch_obj<vector<float>>("pix_zx"),
                  tds.track_branch_obj<vector<float>>("pix_radL"),
                  tds.track_branch_obj<vector<float>>("pix_bbxi"),
                  tds.track_branch_obj<vector<vector<int>>>("pix_trkIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("pix_seeIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("pix_simHitIdx"),
                  tds.track_branch_obj<vector<vector<float>>>("pix_chargeFraction")),
        "pixrec_hits");
}

//#^#=========================================================================
//===================SIM HIT==================================================
//============================================================================
struct SimHit {
    unsigned int   idx;
    unsigned short det;
    unsigned short lay;
    unsigned int   detId;
    float          x;
    float          y;
    float          z;
    int            particle;
    short          process;
    float          eloss;
    float          tof;
    int            simTrkIdx;
    vector<int>    hitIdx;
    vector<int>    hitType;
};

Value<vector<SimHit>>*
register_sim_hits(TrackingDataSet &tds){
    auto builder =
        func<std::vector<SimHit>(vector<unsigned short>, //  det;
                                 vector<unsigned short>, //  lay;
                                 vector<unsigned int>,   //  detId;
                                 vector<float>,          //  x;
                                 vector<float>,          //  y;
                                 vector<float>,          //  z;
                                 vector<int>  ,          //  particle;
                                 vector<short>,          //  process;
                                 vector<float>,          //  eloss;
                                 vector<float>,          //  tof;
                                 vector<int>  ,          //  simTrkIdx;
                                 vector<vector<int>>,    //  hitIdx;
                                 vector<vector<int>>     //  hitType;
            )>("build_sim_hits", FUNC(([](
                 const vector<unsigned short>& det,
                 const vector<unsigned short>& lay,
                 const vector<unsigned int>&   detId,
                 const vector<float>&          x,
                 const vector<float>&          y,
                 const vector<float>&          z,
                 const vector<int>&            particle,
                 const vector<short>&          process,
                 const vector<float>&          eloss,
                 const vector<float>&          tof,
                 const vector<int>&            simTrkIdx,
                 const vector<vector<int>>&    hitIdx,
                 const vector<vector<int>>&    hitType
                 ){
            std::vector<SimHit> sim_hits;
            for(unsigned int i=0; i<det.size(); i++)
                sim_hits.push_back({i,
                                    det[i],
                                    lay[i],
                                    detId[i],
                                    x[i],
                                    y[i],
                                    z[i],
                                    particle[i],
                                    process[i],
                                    eloss[i],
                                    tof[i],
                                    simTrkIdx[i],
                                    hitIdx[i],
                                    hitType[i]});
            return sim_hits;
        })));


    return tup_apply(builder,
        fv::tuple(tds.track_branch_obj<vector<unsigned short>>("simhit_det"),
                  tds.track_branch_obj<vector<unsigned short>>("simhit_lay"),
                  tds.track_branch_obj<vector<unsigned int>>("simhit_detId"),
                  tds.track_branch_obj<vector<float>>("simhit_x"),
                  tds.track_branch_obj<vector<float>>("simhit_y"),
                  tds.track_branch_obj<vector<float>>("simhit_z"),
                  tds.track_branch_obj<vector<int>>("simhit_particle"),
                  tds.track_branch_obj<vector<short>>("simhit_process"),
                  tds.track_branch_obj<vector<float>>("simhit_eloss"),
                  tds.track_branch_obj<vector<float>>("simhit_tof"),
                  tds.track_branch_obj<vector<int>>("simhit_simTrkIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("simhit_hitIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("simhit_hitType")),
        "sim_hits");
}

//#^#=========================================================================
//=======================SEED=================================================
//============================================================================
struct Seed {
    unsigned int   idx;
    short          fitok;
    float          px;
    float          py;
    float          pz;
    float          pt;
    float          eta;
    float          phi;
    float          dxy;
    float          dz;
    float          ptErr;
    float          etaErr;
    float          phiErr;
    float          dxyErr;
    float          dzErr;
    float          chi2;
    int            q;
    unsigned int   nValid;
    unsigned int   nPixel;
    unsigned int   nGlued;
    unsigned int   nStrip;
    unsigned int   algo;
    unsigned int   algoOriginal;
    int            trkIdx;
    vector<float>  shareFrac;
    vector<int>    simTrkIdx;
    vector<int>    hitIdx;
    vector<int>    hitType;
    unsigned int   offset;
    unsigned char  hitsMask;
    int            subDet2;
    float          dRz2;
    float          dPhi2;
    float          dRz2Pos;
    float          dPhi2Pos;
    int            subDet1;
    float          dRz1;
    float          dPhi1;
    float          dRz1Pos;
    float          dPhi1Pos;
    float          hoe1;
    float          hoe2;
    float          superClusterEnergy;
    float          superClusterEta;
    float          superClusterPhi;
    float          superClusterEt;
    int            superClusterIdx;
    unsigned int   ecalDriven;
    unsigned int   trkDriven;
};


Value<vector<Seed>>*
register_seeds(TrackingDataSet &tds){
    auto builder = func<std::vector<Seed>(vector<short>,          // fitok;
                                               vector<float>,          // px;
                                               vector<float>,          // py;
                                               vector<float>,          // pz;
                                               vector<float>,          // pt;
                                               vector<float>,          // eta;
                                               vector<float>,          // phi;
                                               vector<float>,          // dxy;
                                               vector<float>,          // dz;
                                               vector<float>,          // ptErr;
                                               vector<float>,          // etaErr;
                                               vector<float>,          // phiErr;
                                               vector<float>,          // dxyErr;
                                               vector<float>,          // dzErr;
                                               vector<float>,          // chi2;
                                               vector<int>,            // q;
                                               vector<unsigned int>,   // nValid;
                                               vector<unsigned int>,   // nPixel;
                                               vector<unsigned int>,   // nGlued;
                                               vector<unsigned int>,   // nStrip;
                                               vector<unsigned int>,   // algo;
                                               vector<unsigned int>,   // algoOriginal;
                                               vector<int>,            // trkIdx;
                                               vector<vector<float> >, // shareFrac;
                                               vector<vector<int> >,   // simTrkIdx;
                                               vector<vector<int> >,   // hitIdx;
                                               vector<vector<int> >,   // hitType;
                                               vector<unsigned int>,   // offset;
                                               vector<unsigned char>,  // hitsMask;
                                               vector<int>,            // subDet2;
                                               vector<float>,          // dRz2;
                                               vector<float>,          // dPhi2;
                                               vector<float>,          // dRz2Pos;
                                               vector<float>,          // dPhi2Pos;
                                               vector<int>,            // subDet1;
                                               vector<float>,          // dRz1;
                                               vector<float>,          // dPhi1;
                                               vector<float>,          // dRz1Pos;
                                               vector<float>,          // dPhi1Pos;
                                               vector<float>,          // hoe1;
                                               vector<float>,          // hoe2;
                                               vector<float>,          // superClusterEnergy;
                                               vector<float>,          // superClusterEta;
                                               vector<float>,          // superClusterPhi;
                                               vector<float>,          // superClusterEt;
                                               vector<int>,            // superClusterIdx;
                                               vector<unsigned int>,   // ecalDriven;
                                               vector<unsigned int>    // trkDriven;
             )>("build_seeds", FUNC(([](
               const vector<short>&  fitok,
               const vector<float>&  px,
               const vector<float>&  py,
               const vector<float>&  pz,
               const vector<float>&  pt,
               const vector<float>&  eta,
               const vector<float>&  phi,
               const vector<float>&  dxy,
               const vector<float>&  dz,
               const vector<float>&  ptErr,
               const vector<float>&  etaErr,
               const vector<float>&  phiErr,
               const vector<float>&  dxyErr,
               const vector<float>&  dzErr,
               const vector<float>&  chi2,
               const vector<int>&  q,
               const vector<unsigned int>&  nValid,
               const vector<unsigned int>&  nPixel,
               const vector<unsigned int>&  nGlued,
               const vector<unsigned int>&  nStrip,
               const vector<unsigned int>&  algo,
               const vector<unsigned int>&  algoOriginal,
               const vector<int>&  trkIdx,
               const vector<vector<float> >&  shareFrac,
               const vector<vector<int> >&  simTrkIdx,
               const vector<vector<int> >&  hitIdx,
               const vector<vector<int> >&  hitType,
               const vector<unsigned int>&  offset,
               const vector<unsigned char>&  hitsMask,
               const vector<int>&  subDet2,
               const vector<float>&  dRz2,
               const vector<float>&  dPhi2,
               const vector<float>&  dRz2Pos,
               const vector<float>&  dPhi2Pos,
               const vector<int>&  subDet1,
               const vector<float>&  dRz1,
               const vector<float>&  dPhi1,
               const vector<float>&  dRz1Pos,
               const vector<float>&  dPhi1Pos,
               const vector<float>&  hoe1,
               const vector<float>&  hoe2,
               const vector<float>&  superClusterEnergy,
               const vector<float>&  superClusterEta,
               const vector<float>&  superClusterPhi,
               const vector<float>&  superClusterEt,
               const vector<int>&  superClusterIdx,
               const vector<unsigned int>& ecalDriven,
               const vector<unsigned int>& trkDriven){
            std::vector<Seed> seeds;
            for(unsigned int i=0; i<fitok.size(); i++)
                seeds.push_back({i,
                                 fitok[i],
                                 px[i],
                                 py[i],
                                 pz[i],
                                 pt[i],
                                 eta[i],
                                 phi[i],
                                 dxy[i],
                                 dz[i],
                                 ptErr[i],
                                 etaErr[i],
                                 phiErr[i],
                                 dxyErr[i],
                                 dzErr[i],
                                 chi2[i],
                                 q[i],
                                 nValid[i],
                                 nPixel[i],
                                 nGlued[i],
                                 nStrip[i],
                                 algo[i],
                                 algoOriginal[i],
                                 trkIdx[i],
                                 shareFrac[i],
                                 simTrkIdx[i],
                                 hitIdx[i],
                                 hitType[i],
                                 offset[i],
                                 hitsMask[i],
                                 subDet2[i],
                                 dRz2[i],
                                 dPhi2[i],
                                 dRz2Pos[i],
                                 dPhi2Pos[i],
                                 subDet1[i],
                                 dRz1[i],
                                 dPhi1[i],
                                 dRz1Pos[i],
                                 dPhi1Pos[i],
                                 hoe1[i],
                                 hoe2[i],
                                 superClusterEnergy[i],
                                 superClusterEta[i],
                                 superClusterPhi[i],
                                 superClusterEt[i],
                                 superClusterIdx[i],
                                 ecalDriven[i],
                                 trkDriven[i]});
            return seeds;
        })));


    return tup_apply(builder,
        fv::tuple(tds.track_branch_obj<vector<short>>("see_fitok"),
                 tds.track_branch_obj<vector<float>>("see_px"),
                 tds.track_branch_obj<vector<float>>("see_py"),
                 tds.track_branch_obj<vector<float>>("see_pz"),
                 tds.track_branch_obj<vector<float>>("see_pt"),
                 tds.track_branch_obj<vector<float>>("see_eta"),
                 tds.track_branch_obj<vector<float>>("see_phi"),
                 tds.track_branch_obj<vector<float>>("see_dxy"),
                 tds.track_branch_obj<vector<float>>("see_dz"),
                 tds.track_branch_obj<vector<float>>("see_ptErr"),
                 tds.track_branch_obj<vector<float>>("see_etaErr"),
                 tds.track_branch_obj<vector<float>>("see_phiErr"),
                 tds.track_branch_obj<vector<float>>("see_dxyErr"),
                 tds.track_branch_obj<vector<float>>("see_dzErr"),
                 tds.track_branch_obj<vector<float>>("see_chi2"),
                 tds.track_branch_obj<vector<int>>("see_q"),
                 tds.track_branch_obj<vector<unsigned int>>("see_nValid"),
                 tds.track_branch_obj<vector<unsigned int>>("see_nPixel"),
                 tds.track_branch_obj<vector<unsigned int>>("see_nGlued"),
                 tds.track_branch_obj<vector<unsigned int>>("see_nStrip"),
                 tds.track_branch_obj<vector<unsigned int>>("see_algo"),
                 tds.track_branch_obj<vector<unsigned int>>("see_algoOriginal"),
                 tds.track_branch_obj<vector<int>>("see_trkIdx"),
                 tds.track_branch_obj<vector<vector<float> >> ("see_shareFrac"),
                 tds.track_branch_obj<vector<vector<int> >>("see_simTrkIdx"),
                 tds.track_branch_obj<vector<vector<int> >>("see_hitIdx"),
                 tds.track_branch_obj<vector<vector<int> >>("see_hitType"),
                 tds.track_branch_obj<vector<unsigned int>>("see_offset"),
                 tds.track_branch_obj<vector<unsigned char>>("see_hitsMask"),
                 tds.track_branch_obj<vector<int>>("see_subDet2"),
                 tds.track_branch_obj<vector<float>>("see_dRz2"),
                 tds.track_branch_obj<vector<float>>("see_dPhi2"),
                 tds.track_branch_obj<vector<float>>("see_dRz2Pos"),
                 tds.track_branch_obj<vector<float>>("see_dPhi2Pos"),
                 tds.track_branch_obj<vector<int>>("see_subDet1"),
                 tds.track_branch_obj<vector<float>>("see_dRz1"),
                 tds.track_branch_obj<vector<float>>("see_dPhi1"),
                 tds.track_branch_obj<vector<float>>("see_dRz1Pos"),
                 tds.track_branch_obj<vector<float>>("see_dPhi1Pos"),
                 tds.track_branch_obj<vector<float>>("see_hoe1"),
                 tds.track_branch_obj<vector<float>>("see_hoe2"),
                 tds.track_branch_obj<vector<float>>("see_superClusterEnergy"),
                 tds.track_branch_obj<vector<float>>("see_superClusterEta"),
                 tds.track_branch_obj<vector<float>>("see_superClusterPhi"),
                 tds.track_branch_obj<vector<float>>("see_superClusterEt"),
                 tds.track_branch_obj<vector<int>>("see_superClusterIdx"),
                 tds.track_branch_obj<vector<unsigned int>>("see_ecalDriven"),
                 tds.track_branch_obj<vector<unsigned int>>("see_trkDriven")),
        "seeds");
}


//#^#=========================================================================
//=======================TRACK================================================
//============================================================================
struct Track{
    unsigned int  idx;
    float         px;
    float         py;
    float         pz;
    float         pt;
    float         inner_px;
    float         inner_py;
    float         inner_pz;
    float         inner_pt;
    float         outer_px;
    float         outer_py;
    float         outer_pz;
    float         outer_pt;
    float         eta;
    float         lambda;
    float         cotTheta;
    float         phi;
    float         dxy;
    float         dz;
    float         ptErr;
    float         etaErr;
    float         lambdaErr;
    float         phiErr;
    float         dxyErr;
    float         dzErr;
    float         refpoint_x;
    float         refpoint_y;
    float         refpoint_z;
    float         nChi2;
    int           q;
    unsigned int  nValid;
    unsigned int  nInvalid;
    unsigned int  nPixel;
    unsigned int  nStrip;
    unsigned int  nPixelLay;
    unsigned int  nStripLay;
    unsigned int  n3DLay;
    unsigned int  nOuterLost;
    unsigned int  nInnerLost;
    unsigned int  algo;
    unsigned int  originalAlgo;
    ULong64_t     algoMask;
    unsigned int  stopReason;
    short         isHP;
    int           seedIdx;
    float         vtxx;
    float         vtxy;
    float         vtxz;
    vector<float> shareFrac;
    vector<int>   simTrkIdx;
    vector<int>   hitIdx;
    vector<int>   hitType;
    int           genIdx;
    float         genDR;
};

Value<vector<Track>>*
register_tracks(TrackingDataSet &tds){
    auto builder =
        func<std::vector<Track>(vector<float>,         //  px;
                                vector<float>,         //  py;
                                vector<float>,         //  pz;
                                vector<float>,         //  pt;
                                vector<float>,         //  inner_px;
                                vector<float>,         //  inner_py;
                                vector<float>,         //  inner_pz;
                                vector<float>,         //  inner_pt;
                                vector<float>,         //  outer_px;
                                vector<float>,         //  outer_py;
                                vector<float>,         //  outer_pz;
                                vector<float>,         //  outer_pt;
                                vector<float>,         //  eta;
                                vector<float>,         //  lambda;
                                vector<float>,         //  cotTheta;
                                vector<float>,         //  phi;
                                vector<float>,         //  dxy;
                                vector<float>,         //  dz;
                                vector<float>,         //  ptErr;
                                vector<float>,         //  etaErr;
                                vector<float>,         //  lambdaErr;
                                vector<float>,         //  phiErr;
                                vector<float>,         //  dxyErr;
                                vector<float>,         //  dzErr;
                                vector<float>,         //  refpoint_x;
                                vector<float>,         //  refpoint_y;
                                vector<float>,         //  refpoint_z;
                                vector<float>,         //  nChi2;
                                vector<int>,           //  q;
                                vector<unsigned int>,  //  nValid;
                                vector<unsigned int>,  //  nInvalid;
                                vector<unsigned int>,  //  nPixel;
                                vector<unsigned int>,  //  nStrip;
                                vector<unsigned int>,  //  nPixelLay;
                                vector<unsigned int>,  //  nStripLay;
                                vector<unsigned int>,  //  n3DLay;
                                vector<unsigned int>,  //  nOuterLost;
                                vector<unsigned int>,  //  nInnerLost;
                                vector<unsigned int>,  //  algo;
                                vector<unsigned int>,  //  originalAlgo;
                                vector<ULong64_t>,     //  algoMask;
                                vector<unsigned int>,  //  stopReason;
                                vector<short>,         //  isHP;
                                vector<int>,           //  seedIdx;
                                vector<float>,         //  vtxx;
                                vector<float>,         //  vtxy;
                                vector<float>,         //  vtxz;
                                vector<vector<float>>, //  shareFrac;
                                vector<vector<int>>,   //  simTrkIdx;
                                vector<vector<int>>,   //  hitIdx;
                                vector<vector<int>>,   //  hitType;
                                vector<int>,           //  genIdx;
                                vector<float>          //  genDR;
        )>("build_tracks", FUNC(([](const vector<float>&         px,
                                    const vector<float>&         py,
                                    const vector<float>&         pz,
                                    const vector<float>&         pt,
                                    const vector<float>&         inner_px,
                                    const vector<float>&         inner_py,
                                    const vector<float>&         inner_pz,
                                    const vector<float>&         inner_pt,
                                    const vector<float>&         outer_px,
                                    const vector<float>&         outer_py,
                                    const vector<float>&         outer_pz,
                                    const vector<float>&         outer_pt,
                                    const vector<float>&         eta,
                                    const vector<float>&         lambda,
                                    const vector<float>&         cotTheta,
                                    const vector<float>&         phi,
                                    const vector<float>&         dxy,
                                    const vector<float>&         dz,
                                    const vector<float>&         ptErr,
                                    const vector<float>&         etaErr,
                                    const vector<float>&         lambdaErr,
                                    const vector<float>&         phiErr,
                                    const vector<float>&         dxyErr,
                                    const vector<float>&         dzErr,
                                    const vector<float>&         refpoint_x,
                                    const vector<float>&         refpoint_y,
                                    const vector<float>&         refpoint_z,
                                    const vector<float>&         nChi2,
                                    const vector<int>&           q,
                                    const vector<unsigned int>&  nValid,
                                    const vector<unsigned int>&  nInvalid,
                                    const vector<unsigned int>&  nPixel,
                                    const vector<unsigned int>&  nStrip,
                                    const vector<unsigned int>&  nPixelLay,
                                    const vector<unsigned int>&  nStripLay,
                                    const vector<unsigned int>&  n3DLay,
                                    const vector<unsigned int>&  nOuterLost,
                                    const vector<unsigned int>&  nInnerLost,
                                    const vector<unsigned int>&  algo,
                                    const vector<unsigned int>&  originalAlgo,
                                    const vector<ULong64_t>&     algoMask,
                                    const vector<unsigned int>&  stopReason,
                                    const vector<short>&         isHP,
                                    const vector<int>&           seedIdx,
                                    const vector<float>&         vtxx,
                                    const vector<float>&         vtxy,
                                    const vector<float>&         vtxz,
                                    const vector<vector<float>>& shareFrac,
                                    const vector<vector<int>>&   simTrkIdx,
                                    const vector<vector<int>>&   hitIdx,
                                    const vector<vector<int>>&   hitType,
                                    const vector<int>&           genIdx,
                                    const vector<float>&         genDR){
            std::vector<Track> tracks;
            for(unsigned int i=0; i<px.size(); i++)
                tracks.push_back({i,
                                  px[i],
                                  py[i],
                                  pz[i],
                                  pt[i],
                                  inner_px[i],
                                  inner_py[i],
                                  inner_pz[i],
                                  inner_pt[i],
                                  outer_px[i],
                                  outer_py[i],
                                  outer_pz[i],
                                  outer_pt[i],
                                  eta[i],
                                  lambda[i],
                                  cotTheta[i],
                                  phi[i],
                                  dxy[i],
                                  dz[i],
                                  ptErr[i],
                                  etaErr[i],
                                  lambdaErr[i],
                                  phiErr[i],
                                  dxyErr[i],
                                  dzErr[i],
                                  refpoint_x[i],
                                  refpoint_y[i],
                                  refpoint_z[i],
                                  nChi2[i],
                                  q[i],
                                  nValid[i],
                                  nInvalid[i],
                                  nPixel[i],
                                  nStrip[i],
                                  nPixelLay[i],
                                  nStripLay[i],
                                  n3DLay[i],
                                  nOuterLost[i],
                                  nInnerLost[i],
                                  algo[i],
                                  originalAlgo[i],
                                  algoMask[i],
                                  stopReason[i],
                                  isHP[i],
                                  seedIdx[i],
                                  vtxx[i],
                                  vtxy[i],
                                  vtxz[i],
                                  shareFrac[i],
                                  simTrkIdx[i],
                                  hitIdx[i],
                                  hitType[i],
                                  genIdx[i],
                                  genDR[i]});
            return tracks;
        })));
    return tup_apply(builder,
        fv::tuple(tds.track_branch_obj<vector<float>>("trk_px"),
                  tds.track_branch_obj<vector<float>>("trk_py"),
                  tds.track_branch_obj<vector<float>>("trk_pz"),
                  tds.track_branch_obj<vector<float>>("trk_pt"),
                  tds.track_branch_obj<vector<float>>("trk_inner_px"),
                  tds.track_branch_obj<vector<float>>("trk_inner_py"),
                  tds.track_branch_obj<vector<float>>("trk_inner_pz"),
                  tds.track_branch_obj<vector<float>>("trk_inner_pt"),
                  tds.track_branch_obj<vector<float>>("trk_outer_px"),
                  tds.track_branch_obj<vector<float>>("trk_outer_py"),
                  tds.track_branch_obj<vector<float>>("trk_outer_pz"),
                  tds.track_branch_obj<vector<float>>("trk_outer_pt"),
                  tds.track_branch_obj<vector<float>>("trk_eta"),
                  tds.track_branch_obj<vector<float>>("trk_lambda"),
                  tds.track_branch_obj<vector<float>>("trk_cotTheta"),
                  tds.track_branch_obj<vector<float>>("trk_phi"),
                  tds.track_branch_obj<vector<float>>("trk_dxy"),
                  tds.track_branch_obj<vector<float>>("trk_dz"),
                  tds.track_branch_obj<vector<float>>("trk_ptErr"),
                  tds.track_branch_obj<vector<float>>("trk_etaErr"),
                  tds.track_branch_obj<vector<float>>("trk_lambdaErr"),
                  tds.track_branch_obj<vector<float>>("trk_phiErr"),
                  tds.track_branch_obj<vector<float>>("trk_dxyErr"),
                  tds.track_branch_obj<vector<float>>("trk_dzErr"),
                  tds.track_branch_obj<vector<float>>("trk_refpoint_x"),
                  tds.track_branch_obj<vector<float>>("trk_refpoint_y"),
                  tds.track_branch_obj<vector<float>>("trk_refpoint_z"),
                  tds.track_branch_obj<vector<float>>("trk_nChi2"),
                  tds.track_branch_obj<vector<int>>("trk_q"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nValid"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nInvalid"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nPixel"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nStrip"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nPixelLay"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nStripLay"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_n3DLay"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nOuterLost"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_nInnerLost"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_algo"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_originalAlgo"),
                  tds.track_branch_obj<vector<ULong64_t>>("trk_algoMask"),
                  tds.track_branch_obj<vector<unsigned int>>("trk_stopReason"),
                  tds.track_branch_obj<vector<short>>("trk_isHP"),
                  tds.track_branch_obj<vector<int>>("trk_seedIdx"),
                  tds.track_branch_obj<vector<float>>("trk_vtxx"),
                  tds.track_branch_obj<vector<float>>("trk_vtxy"),
                  tds.track_branch_obj<vector<float>>("trk_vtxz"),
                  tds.track_branch_obj<vector<vector<float>>>("trk_shareFrac"),
                  tds.track_branch_obj<vector<vector<int>>>("trk_simTrkIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("trk_hitIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("trk_hitType"),
                  tds.track_branch_obj<vector<int>>("trk_genIdx"),
                  tds.track_branch_obj<vector<float>>("trk_genDR")),
        "tracks");
}


//#^#=========================================================================
//===================SIM TRACK================================================
//============================================================================
struct SimTrack{
    unsigned int   idx;
    int           event;
    int           bunchCrossing;
    int           pdgId;
    float         px;
    float         py;
    float         pz;
    float         pt;
    float         eta;
    float         phi;
    float         pca_pt;
    float         pca_eta;
    float         pca_lambda;
    float         pca_cotTheta;
    float         pca_phi;
    float         pca_dxy;
    float         pca_dz;
    int           q;
    unsigned int  nValid;
    unsigned int  nPixel;
    unsigned int  nStrip;
    unsigned int  nLay;
    unsigned int  nPixelLay;
    unsigned int  n3DLay;
    vector<int>   trkIdx;
    vector<float> shareFrac;
    int           parentVtxIdx;
    vector<int>   decayVtxIdx;
    vector<int>   simHitIdx;
};


Value<vector<SimTrack>>*
register_sim_tracks(TrackingDataSet &tds){
    auto builder =
        func<std::vector<SimTrack>(vector<int>,           //  event;
                                   vector<int>,           //  bunchCrossing;
                                   vector<int>,           //  pdgId;
                                   vector<float>,         //  px;
                                   vector<float>,         //  py;
                                   vector<float>,         //  pz;
                                   vector<float>,         //  pt;
                                   vector<float>,         //  eta;
                                   vector<float>,         //  phi;
                                   vector<float>,         //  pca_pt;
                                   vector<float>,         //  pca_eta;
                                   vector<float>,         //  pca_lambda;
                                   vector<float>,         //  pca_cotTheta;
                                   vector<float>,         //  pca_phi;
                                   vector<float>,         //  pca_dxy;
                                   vector<float>,         //  pca_dz;
                                   vector<int>,           //  q;
                                   vector<unsigned int>,  //  nValid;
                                   vector<unsigned int>,  //  nPixel;
                                   vector<unsigned int>,  //  nStrip;
                                   vector<unsigned int>,  //  nLay;
                                   vector<unsigned int>,  //  nPixelLay;
                                   vector<unsigned int>,  //  n3DLay;
                                   vector<vector<int>>,   //  trkIdx;
                                   vector<vector<float>>, //  shareFrac;
                                   vector<int>,           //  parentVtxIdx;
                                   vector<vector<int>>,   //  decayVtxIdx;
                                   vector<vector<int>>    //  simHitIdx;
            )>("build_sim_tracks", FUNC(([](
               const vector<int>&           event,
               const vector<int>&           bunchCrossing,
               const vector<int>&           pdgId,
               const vector<float>&         px,
               const vector<float>&         py,
               const vector<float>&         pz,
               const vector<float>&         pt,
               const vector<float>&         eta,
               const vector<float>&         phi,
               const vector<float>&         pca_pt,
               const vector<float>&         pca_eta,
               const vector<float>&         pca_lambda,
               const vector<float>&         pca_cotTheta,
               const vector<float>&         pca_phi,
               const vector<float>&         pca_dxy,
               const vector<float>&         pca_dz,
               const vector<int>&           q,
               const vector<unsigned int>&  nValid,
               const vector<unsigned int>&  nPixel,
               const vector<unsigned int>&  nStrip,
               const vector<unsigned int>&  nLay,
               const vector<unsigned int>&  nPixelLay,
               const vector<unsigned int>&  n3DLay,
               const vector<vector<int>>&   trkIdx,
               const vector<vector<float>>& shareFrac,
               const vector<int>&           parentVtxIdx,
               const vector<vector<int>>&   decayVtxIdx,
               const vector<vector<int>>&   simHitIdx){
            std::vector<SimTrack> sim_tracks;
            for(unsigned int i=0; i<event.size(); i++)
                sim_tracks.push_back({i,
                                      event[i],
                                      bunchCrossing[i],
                                      pdgId[i],
                                      px[i],
                                      py[i],
                                      pz[i],
                                      pt[i],
                                      eta[i],
                                      phi[i],
                                      pca_pt[i],
                                      pca_eta[i],
                                      pca_lambda[i],
                                      pca_cotTheta[i],
                                      pca_phi[i],
                                      pca_dxy[i],
                                      pca_dz[i],
                                      q[i],
                                      nValid[i],
                                      nPixel[i],
                                      nStrip[i],
                                      nLay[i],
                                      nPixelLay[i],
                                      n3DLay[i],
                                      trkIdx[i],
                                      shareFrac[i],
                                      parentVtxIdx[i],
                                      decayVtxIdx[i],
                                      simHitIdx[i]});
            return sim_tracks;
        })));
    return tup_apply(builder,
        fv::tuple(tds.track_branch_obj<vector<int>>("sim_event"),
                  tds.track_branch_obj<vector<int>>("sim_bunchCrossing"),
                  tds.track_branch_obj<vector<int>>("sim_pdgId"),
                  tds.track_branch_obj<vector<float>>("sim_px"),
                  tds.track_branch_obj<vector<float>>("sim_py"),
                  tds.track_branch_obj<vector<float>>("sim_pz"),
                  tds.track_branch_obj<vector<float>>("sim_pt"),
                  tds.track_branch_obj<vector<float>>("sim_eta"),
                  tds.track_branch_obj<vector<float>>("sim_phi"),
                  tds.track_branch_obj<vector<float>>("sim_pca_pt"),
                  tds.track_branch_obj<vector<float>>("sim_pca_eta"),
                  tds.track_branch_obj<vector<float>>("sim_pca_lambda"),
                  tds.track_branch_obj<vector<float>>("sim_pca_cotTheta"),
                  tds.track_branch_obj<vector<float>>("sim_pca_phi"),
                  tds.track_branch_obj<vector<float>>("sim_pca_dxy"),
                  tds.track_branch_obj<vector<float>>("sim_pca_dz"),
                  tds.track_branch_obj<vector<int>>("sim_q"),
                  tds.track_branch_obj<vector<unsigned int>>("sim_nValid"),
                  tds.track_branch_obj<vector<unsigned int>>("sim_nPixel"),
                  tds.track_branch_obj<vector<unsigned int>>("sim_nStrip"),
                  tds.track_branch_obj<vector<unsigned int>>("sim_nLay"),
                  tds.track_branch_obj<vector<unsigned int>>("sim_nPixelLay"),
                  tds.track_branch_obj<vector<unsigned int>>("sim_n3DLay"),
                  tds.track_branch_obj<vector<vector<int>>>("sim_trkIdx"),
                  tds.track_branch_obj<vector<vector<float>>>("sim_shareFrac"),
                  tds.track_branch_obj<vector<int>>("sim_parentVtxIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("sim_decayVtxIdx"),
                  tds.track_branch_obj<vector<vector<int>>>("sim_simHitIdx")),
        "sim_tracks");
}

//#^#=========================================================================
//==============SUPER CLUSTERS================================================
//============================================================================
struct SuperCluster {
    unsigned int          idx;
    float                 e;
    float                 px;
    float                 py;
    float                 pz;
    float                 x;
    float                 y;
    float                 z;
    vector<int>           charge;
    vector<int>           lay1;
    vector<int>           lay2;
    vector<int>           ladder_blade1;
    vector<int>           ladder_blade2;
    vector<int>           subDet1;
    vector<int>           subDet2;
    vector<float>         dRz1;
    vector<float>         dPhi1;
    vector<float>         dRz2;
    vector<float>         dPhi2;
    vector<int>           seedType;
    vector<int>           seedHitIdx1;
    vector<int>           seedHitIdx2;
};

Value<vector<SuperCluster>>*
register_super_clusters(TrackingDataSet &tds){
    auto builder =
        func<std::vector<SuperCluster>(vector<float>,                 // e,
                                       vector<float>,                 // px,
                                       vector<float>,                 // py,
                                       vector<float>,                 // pz,
                                       vector<float>,                 // x,
                                       vector<float>,                 // y,
                                       vector<float>,                 // z,
                                       vector<vector<int>>,           // charge;
                                       vector<vector<int>>,           // lay1;
                                       vector<vector<int>>,           // lay2;
                                       vector<vector<int>>,           // ladder_blade1;
                                       vector<vector<int>>,           // ladder_blade2;
                                       vector<vector<int>>,           // subDet1;
                                       vector<vector<int>>,           // subDet2;
                                       vector<vector<float>>,         // dRz1;
                                       vector<vector<float>>,         // dPhi1;
                                       vector<vector<float>>,         // dRz2;
                                       vector<vector<float>>,         // dPhi2;
                                       vector<vector<int>>,           // seedType;
                                       vector<vector<int>>,           // seedHitIdx1;
                                       vector<vector<int>>            // seedHitIdx1;
                                        )>("build_super_clusters",
        FUNC(([](const vector<float>&                  e,
                 const vector<float>&                  px,
                 const vector<float>&                  py,
                 const vector<float>&                  pz,
                 const vector<float>&                  x,
                 const vector<float>&                  y,
                 const vector<float>&                  z,
                 const vector<vector<int>>&            charge,
                 const vector<vector<int>>&            lay1,
                 const vector<vector<int>>&            lay2,
                 const vector<vector<int>>&            ladder_blade1,
                 const vector<vector<int>>&            ladder_blade2,
                 const vector<vector<int>>&            subDet1,
                 const vector<vector<int>>&            subDet2,
                 const vector<vector<float>>&          dRz1,
                 const vector<vector<float>>&          dPhi1,
                 const vector<vector<float>>&          dRz2,
                 const vector<vector<float>>&          dPhi2,
                 const vector<vector<int>>&            seedType,
                 const vector<vector<int>>&            seedHitIdx1,
                 const vector<vector<int>>&            seedHitIdx2){
            std::vector<SuperCluster> super_clusters;
            for(unsigned int i=0; i<e.size(); i++)
                super_clusters.push_back({i,
                                          e[i],
                                          px[i],
                                          py[i],
                                          pz[i],
                                          x[i],
                                          y[i],
                                          z[i],
                                          charge[i],
                                          lay1[i],
                                          lay2[i],
                                          ladder_blade1[i],
                                          ladder_blade2[i],
                                          subDet1[i],
                                          subDet2[i],
                                          dRz1[i],
                                          dPhi1[i],
                                          dRz2[i],
                                          dPhi2[i],
                                          seedType[i],
                                          seedHitIdx1[i],
                                          seedHitIdx2[i]});
            return super_clusters;
        })));

    return tup_apply(builder,
        fv::tuple(tds.track_branch_obj<vector<float>>("scl_e"),
                  tds.track_branch_obj<vector<float>>("scl_px"),
                  tds.track_branch_obj<vector<float>>("scl_py"),
                  tds.track_branch_obj<vector<float>>("scl_pz"),
                  tds.track_branch_obj<vector<float>>("scl_x"),
                  tds.track_branch_obj<vector<float>>("scl_y"),
                  tds.track_branch_obj<vector<float>>("scl_z"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_charge"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_lay1"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_lay2"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_ladder_blade1"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_ladder_blade2"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_subDet1"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_subDet2"),
                  tds.track_branch_obj<vector<vector<float>>>("scl_dRz1"),
                  tds.track_branch_obj<vector<vector<float>>>("scl_dPhi1"),
                  tds.track_branch_obj<vector<vector<float>>>("scl_dRz2"),
                  tds.track_branch_obj<vector<vector<float>>>("scl_dPhi2"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_seedType"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_seedHitIdx1"),
                  tds.track_branch_obj<vector<vector<int>>>("scl_seedHitIdx2")
                  ), "super_clusters");
}