int ChargedHiggsQCDPurity::analyze(Event*e,string systname)
{
    #ifdef VERBOSE
    if (VERBOSE >0 ) cout<<"[ChargedHiggsQCDPurity]::[analyze]::[DEBUG1] start analyze event"<<endl;
    #endif
    string label = GetLabel(e);
    // do not distinguish between data and mc, 
    // so we can run closures
    // Fill Real Iso 
    Tau *t = e->GetTau(0);
    // Fill Inverted Iso
    Tau *tInv = e->GetTauInvIso(0);

    e->ApplyTopReweight();

    e->ApplyWReweight();

    #ifdef VERBOSE
    if (VERBOSE >0 ) cout<<"[ChargedHiggsQCDPurity]::[analyze]::[DEBUG1] is Tau? "<< (t==NULL) <<endl;
    if (VERBOSE >0 ) cout<<"[ChargedHiggsQCDPurity]::[analyze]::[DEBUG1] is TauInv? "<< (tInv == NULL)<<endl;
    #endif

    // --- take the selection from the tau nu analysis
    CutSelector direct; 
        direct.SetMask(ChargedHiggsTauNu::MaxCut-1);
        direct.SetCut(ChargedHiggsTauNu::Selection(e,true,false,is80X,isLightMass));
    CutSelector inverse;
        inverse.SetMask(ChargedHiggsTauNu::MaxCut-1);
        inverse.SetCut(ChargedHiggsTauNu::Selection(e,false,false,is80X,isLightMass));

    // TODO:
    // * what do I do with event with a Tau and an Inv tau? -> DY ? 
    // * put a limit on the TauInv sideband ? 3.0 -20 GeV

    bool passDirectLoose=direct.passAllUpTo(ChargedHiggsTauNu::ThreeJets);
   bool passInverseLoose=inverse.passAllUpTo(ChargedHiggsTauNu::ThreeJets);

    
  // bool passDirectLoose=direct.passAllUpTo(ChargedHiggsTauNu::OneBjet);
  // bool passInverseLoose=inverse.passAllUpTo(ChargedHiggsTauNu::OneBjet);
    //#warning QCD BJets
    //LogN(__FUNCTION__,"WARNING","ONE B REQUIRED FOR QCD LOOSE",10);
    
    
    // check minimal selection: Three bjets
    if ( not passDirectLoose
         and not  passInverseLoose
       ) return EVENT_NOT_USED;
   
   
    bool passPrescale=false;
    if(e->GetWeight()->GetMC().find("ST") != string::npos || e->GetWeight()->GetMC().find("WZ") != string::npos || e->GetWeight()->GetMC().find("WW") != string::npos || e->GetWeight()->GetMC().find("ZZ") != string::npos) {
        
        passPrescale=true; // set trigger, but apply SF!
 
        // Met SF only for pT > 20 (only for MC)
        string metLegSF = "metLegData";
        if(not e->ExistSF(metLegSF)) Log(__FUNCTION__,"WARING" ,"No Tau metLeg SF");
        else if(e->GetMet().Pt()>20 and not e->IsRealData()) {
            e->SetPtEtaSF(metLegSF, e->GetMet().Pt(), 0);
            e->ApplySF(metLegSF);
        }
    }
    else {
        

        // Apply MET leg SF (only on MC)
        // NEGLECT IT
        /*
        string metLegSF = "metLeg";
        if(not e->ExistSF(metLegSF)) Log(__FUNCTION__,"WARING" ,"No Tau metLeg SF");
        else if(e->GetMet().Pt()>20 and not e->IsRealData()) {
            e->SetPtEtaSF(metLegSF, e->GetMet().Pt(), 0);
            e->ApplySF(metLegSF);
        }
        */
        if(e->IsTriggered("HLT_LooseIsoPFTau50_Trk30_eta2p1_MET90")) passPrescale=true;   
    }
   

    //  USE PRESCALE PATH ONLY FOR THE "inclusive/Loose" selection
    //bool passPrescale=false;
    //if (not e->IsRealData()) passPrescale=true;
    //if (  e->IsTriggered("HLT_LooseIsoPFTau50_Trk30_eta2p1_v") ) passPrescale=true;
    //#warning MET80 TRigger in QCD
    //if (  e->IsTriggered("HLT_LooseIsoPFTau50_Trk30_eta2p1_MET90") ) passPrescale=true;
    //LogN(__FUNCTION__,"WARNING","MET 80 in QCD Loose",10);
    //
    //bool passMatchDirect=true;
    //bool passMatchInverse=true;
    
    #warning Tau Match
    bool passMatchDirect=false;
    bool passMatchInverse=false;
    if (e->IsRealData()) { passMatchDirect=true; passMatchInverse=true;}
    else {  
        if (e->GetTau(0) !=NULL and e->GetTau(0)->Rematch(e)==15) passMatchDirect=true;
        if (e->GetTauInvIso(0) !=NULL and e->GetTauInvIso(0)->Rematch(e)==15) passMatchInverse=true;
    }

    /*
    if (not e->IsRealData() )
    {
        if (passDirectLoose)
        {
            e->SetPtEtaSF("antiE",e->GetTau(0)->Pt(),e->GetTau(0)->Eta() );
            e->ApplySF("antiE");
        }
        else if (passInverseLoose) // don't apply them twice
        {
            e->SetPtEtaSF("antiE",e->GetTauInvIso(0)->Pt(),e->GetTauInvIso(0)->Eta() );
            e->ApplySF("antiE");
        }
    }
    */

    //--------------

    if (t != NULL and passMatchDirect and passDirectLoose and passPrescale) // direct
    {
        float pt = t->Pt();
        int flavor= t->Rematch(e);

        if (pt  > 8000 or pt <0 )  Log(__FUNCTION__,"INFO",Form("strange event : tau Pt=%.0f",pt));

        string hist = HistName(pt,true, false);
        Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
        hist = HistName(pt,true, false,"Uperp");
        Fill( dir+hist +"_"+label,systname, Upar(e,t), e->weight() );
        hist = HistName(pt,true, false,"Upar");
        Fill( dir+hist +"_"+label,systname, Uperp(e,t), e->weight() );
        hist = HistName(pt, true, false, "TauPt") ;
        Fill( dir+hist +"_"+label,systname, t->Pt(), e->weight() );

        /*
        hist = HistName(pt, true, false) ;
        if (flavor == 15) hist += "_T";
        else if (flavor == 21 ) hist+="_G";
        else if (flavor <5 and flavor != 0 ) hist+="_Q";
        else hist += "_U";
        Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
         */

        hist = HistName(pt, true, false) ;
        if (t->GetNProng()==1) hist +="_1p";
        else hist+="_3p";
        Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );

        { // CONTROL PLOTS -- LOOSE SELECTION
            string hist= "TauPt_Control";
            Fill( dir+hist +"_"+label,systname, t->Pt(), e->weight() );
            hist= "EtMiss_Control";
            Fill( dir+hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
        }

    }

    if (tInv != NULL and passMatchInverse and passInverseLoose and passPrescale) // inv iso
    {
        float pt = tInv->Pt();
        int flavor= tInv->Rematch(e);
        if (pt  > 8000 or pt <0 )  Log(__FUNCTION__,"INFO",Form("strange event : tau Pt=%.0f",pt));
        string hist = HistName(pt,false,false);
        Fill( dir+hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
        hist = HistName(pt,false, false,"Uperp");
        Fill( dir+hist +"_"+label,systname, Upar(e,tInv), e->weight() );
        hist = HistName(pt,false, false,"Upar");
        Fill( dir+hist +"_"+label,systname, Uperp(e,tInv), e->weight() );
        hist = HistName(pt, false, false, "TauPt") ;
        Fill( dir+hist +"_"+label,systname, tInv->Pt(), e->weight() );

        /*
        hist = HistName(pt, false, false) ;
        if (flavor == 15) hist += "_T";
        else if (flavor == 21 ) hist+="_G";
        else if (flavor <5 and flavor != 0 ) hist+="_Q";
        else hist += "_U";
        Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
         */
        hist = HistName(pt, false, false) ;
        if (tInv->GetNProng()==1) hist+="_1p";
        else hist+="_3p";
        Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
    }

    // not in the LOOSE --- BTAG SF, only MC
    //#warning no-btag-sf
    if (not e->IsRealData()) e->ApplyBTagSF(0);// 0=loos wp
    // -------------------------- FULL SELECTION -----------------------------------------------
    //
    if (t!=NULL and passMatchDirect and not e->IsRealData()) 
    {
        e->ApplyTauSF(t, false); 
    }
    
    // N minus one direct
    if (t!=NULL and passMatchDirect and direct.passAllExcept(ChargedHiggsTauNu::Met) ) 
        {
            Fill( none + "EtMiss" +"_"+label,systname, e->GetMet().Pt(), e->weight() );
        }

    if (t!=NULL and passMatchDirect and direct.passAllExcept(ChargedHiggsTauNu::AngRbb) ) 
        {
            Fill( none + "RbbMin" +"_"+label,systname, e->RbbMin(), e->weight() );
        }

    if (t!=NULL and passMatchDirect and direct.passAllExcept(ChargedHiggsTauNu::AngColl) ) 
        {
            Fill( none + "RCollMin" +"_"+label,systname, e->RCollMin(), e->weight() );
        }
    
    if (t!=NULL and passMatchDirect and direct.passAllExcept(ChargedHiggsTauNu::OneTau) ) 
        {
            Fill( none + "Tau1Pt" +"_"+label,systname, t->Pt(), e->weight() );
        }

    if (t!=NULL and passMatchDirect and direct.passAll() ) 
    {
            //if ( not e->IsRealData()) e->ApplySF("btag");
            #ifdef VERBOSE
            if (VERBOSE >0 ) Log(__FUNCTION__,"DEBUG", "is tau pass full selection");
            #endif
            //if(e->IsRealData() and (systname=="NONE" or systname=="") ) Log(__FUNCTION__,"SYNC",Form("%d,%d,%ld",e->runNum(),e->lumiNum(),e->eventNum()) );
            float pt = t->Pt();
            int flavor= t->Rematch(e);
            string hist = HistName(pt,true,true);  
            Fill(dir+hist+"_"+label,systname, e->GetMet().Pt() ,e->weight());

            hist= "Mt"; //UNBLIND --------
            if ( Unblind(e) ) Fill(dir+hist+"_"+label,systname, e->Mt() ,e->weight());

            hist = HistName(pt,true, true,"Uperp");
            Fill( dir+hist +"_"+label,systname, Upar(e,t), e->weight() );
            hist = HistName(pt,true, true,"Upar");
            Fill( dir+hist +"_"+label,systname, Uperp(e,t), e->weight() );

            hist = HistName(pt, true,true) ;
            if (flavor == 15) hist += "_T";
            else if (flavor == 21 ) hist+="_G";
            else if (flavor <5 and flavor != 0 ) hist+="_Q";
            else hist += "_U";
            Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );

            hist = HistName(pt, true,true) ;
            if (t->GetNProng()==1) hist+="_1p";
            else hist+="_3p";
            Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight() );
    }

    // ---------------------- INF TAU SF 
    //
    if (tInv != NULL and passMatchInverse and passInverseLoose ){ // USE weight(false) to apply TF on data!
        float pt = tInv->Pt();                                                   
        //const string sf="tauinviso";
        string sfname="tauinvisospline";
        //if (tInv->GetNProng() ==1 ) sfname+="_1p";
        //else sfname+="_3p";
        // if the SF don't exist go on, but don't fill inconsistent events
        if( not e->ExistSF(sfname) ){
            LogN(__FUNCTION__,"WARNING","Tau inviso SF does not exist",10);
            return EVENT_NOT_USED;
        }
        e->SetPtEtaSF(sfname,tInv->Pt(),tInv->Eta());
        e->ApplySF(sfname); // only in weight(false) sf are applied in data

        if(inverse.passAllUpTo(ChargedHiggsTauNu::ThreeJets) && inverse.pass(ChargedHiggsTauNu::Trigger)) Fill("ChargedHiggsTauNu/CutFlowQCD/CutFlowQCD_"+label,systname,0,e->weight(false));
        if(inverse.passAllUpTo(ChargedHiggsTauNu::OneBjet) && inverse.pass(ChargedHiggsTauNu::Trigger)) Fill("ChargedHiggsTauNu/CutFlowQCD/CutFlowQCD_"+label,systname,1,e->weight(false));
        if(inverse.passAllUpTo(ChargedHiggsTauNu::Met)) Fill("ChargedHiggsTauNu/CutFlowQCD/CutFlowQCD_"+label,systname,2,e->weight(false));
        if(inverse.passAllUpTo(ChargedHiggsTauNu::AngRbb)) Fill("ChargedHiggsTauNu/CutFlowQCD/CutFlowQCD_"+label,systname,3,e->weight(false));
     
        
        
        //Log(__FUNCTION__,"DEBUG",string("syst name is ") + systname + Form("weight is %f",e->weight(false)) );
        if (tInv != NULL and passInverseLoose and passPrescale){ // CONTROL PLOTS -- LOOSE SELECTION
            string hist= "TauPt_IsoInv_Control";
            Fill( dir+hist +"_"+label,systname, tInv->Pt(), e->weight(false) );
            hist= "EtMiss_IsoInv_Control";
            Fill( dir+hist +"_"+label,systname, e->GetMet().Pt(), e->weight(false) );
        }

        if (inverse.passAllExcept(ChargedHiggsTauNu::Met))
        {
            //if (not e->IsTriggered("HLT_LooseIsoPFTau50_Trk30_eta2p1_MET120") ) Log(__FUNCTION__,"ERROR","Event Is NOT Triggered!!! Why am I here?");
            //Log(__FUNCTION__,"DEBUG",Form("N-1 MET Selection InvIso w=%.4f",e->weight(false)));
            Fill( none + "EtMissIsoInv" +"_"+label,systname, e->GetMet().Pt(), e->weight(false) );

        }

        if (inverse.passAllExcept(ChargedHiggsTauNu::AngRbb) ) 
            {
                Fill( none + "RbbMinIsoInv" +"_"+label,systname, e->RbbMin(3,tInv), e->weight(false) );
            }

        if (inverse.passAllExcept(ChargedHiggsTauNu::AngColl) ) 
            {
                Fill( none + "RCollMinIsoInv" +"_"+label,systname, e->RCollMin(3,tInv), e->weight(false) );
            }
        
        
        if (inverse.passAllExcept(ChargedHiggsTauNu::OneBjet) ) 
        {
            Fill( none + "NBjetsIsoInv" +"_"+label,systname, e->Bjets(), e->weight(false) );
        }
        
        // TauPtIsoInv
        if (inverse.passAllExcept(ChargedHiggsTauNu::OneTau) ) 
        {
            Fill( none + "Tau1PtIsoInv" +"_"+label,systname, pt, e->weight(false) );
        }        

        // remove trigger & met
        /*
        unsigned mymask =  0 ;
        for(unsigned i=0;i<ChargedHiggsTauNu::MaxCut;++i){
            if (i==ChargedHiggsTauNu::Trigger) continue;
            if (i==ChargedHiggsTauNu::Met) continue;
            mymask |= (1<<i); // set all 1
        }

        if (passPrescale and passInverseLoose and inverse.passMask(mymask) )
        {
            // On data avoid R fact -- n minus one
            string hist=HistName(pt, false, true)+"_NoR";
            Fill(dir+hist+"_"+label,systname, e->GetMet().Pt() ,e->weight(true));
        }
         */

        if (inverse.passAll()) { // FULL SELECTION
            //if ( not e->IsRealData()) e->ApplySF("btag");
            #ifdef VERBOSE
            if (VERBOSE >0 ) Log(__FUNCTION__,"DEBUG","is tauInv full selection");
            #endif


            if (e->weight(false) == 0 )Log(__FUNCTION__,"WARNING","event weight after SF is 0 ");

            int flavor= tInv->Rematch(e);
            string hist = HistName(pt,false,true);                                   
            Fill(dir+hist+"_"+label,systname, e->GetMet().Pt() ,e->weight(false));


            //hist = HistName(pt,false,true,"Mt");  
            hist = "MtIsoInv";
            Fill(dir+hist+"_"+label,systname, e->Mt(Event::MtTauInv) ,e->weight(false));
            hist = HistName(pt,false, true,"Uperp");
            Fill( dir+hist +"_"+label,systname, Upar(e,tInv), e->weight(false) );
            hist = HistName(pt,false, true,"Upar");
            Fill( dir+hist +"_"+label,systname, Uperp(e,tInv), e->weight(false) );

            /*
            hist = HistName(pt, false, true) ;
            if (flavor == 15) hist += "_T";
            else if (flavor == 21 ) hist+="_G";
            else if (flavor <5 and flavor != 0 ) hist+="_Q";
            else hist += "_U";
            Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight(false) );
            */
            hist = HistName(pt, false, true) ;
            if (tInv->GetNProng() ==1 ) hist+="_1p";
            else hist+="_3p";
            Fill( dir + hist +"_"+label,systname, e->GetMet().Pt(), e->weight(false) );
             
        } // inverse.passAll
    } // tInv


    return EVENT_NOT_USED;
}
unsigned ChargedHiggsTauNu::Selection(Event *e, bool direct, bool muon) {
    
    CutSelector cut; 
    cut.SetMask(MaxCut-1);
    cut.SetCutBit(Total);

    std::unique_ptr<Tau> garbage; //if created will be deleted, garbage collector

    Tau *t =NULL;
    if (direct and not muon) t = e->GetTau(0); 
    else if(not muon) t = e->GetTauInvIso(0);
    else {
        Lepton*m=e->GetMuon(0);
        //Construct a fake tau
        if (m!=NULL){
            t=new Tau();
            t->SetP4( m->GetP4() );
            t-> SetIso(0);
            t-> SetType(15);
            t-> SetIso2(0);
            t-> SetId(1);
            t-> SetIdEle(1);
            t-> SetIdMu(1);
            t-> SetIdIso(1);
            garbage.reset(t); // make sure it will be deleted
        }
    }

    // Apply matching to a pileup-ided jet for taus, 
    // both for direct and inversely isolated
    /*
    if (not muon and t != NULL){
        Jet *j = e->GetMatchedBareJet(t);
        // match a tau to a well pu-ided jet.
        if (j==NULL) t=NULL;
        else {
            float aeta= abs(j->Eta());
            float pt = j->GetP4Dirty().Pt(); // no syst
            float puId = j -> GetPuId();
            if ( aeta< 2.5){
                if (pt >=30 and pt< 50 and puId <-0.89)  t=NULL;
                if (pt >=10 and pt< 30 and puId <-0.97)  t=NULL;
            }
            else if (aeta < 2.75){
                if (pt >=30 and pt< 50 and puId <-0.52)  t=NULL;
                if (pt >=10 and pt< 30 and puId <-0.68)  t=NULL;
            }
            else if (aeta < 3.00){
                if (pt >=30 and pt< 50 and puId <-0.38)  t=NULL;
                if (pt >=10 and pt< 30 and puId <-0.53)  t=NULL;
            }
            else if (aeta < 5.00){
                if (pt >=30 and pt< 50 and puId <-0.30)  t=NULL;
                if (pt >=10 and pt< 30 and puId <-0.47)  t=NULL;
            }
        }
    }
    */
    

    Object *sub = NULL;
    if (direct and not muon) sub = e->GetTau(1);
    if (muon) sub=e->GetMuon(1);

    //------------- TRIGGER -----------
    {
        if ( not muon and not singleTauTrigger and e->IsTriggered("HLT_LooseIsoPFTau50_Trk30_eta2p1_MET110"))  cut.SetCutBit(Trigger);
        /*HLT_VLooseIsoPFTau120_Trk50_eta2p1_v
         * HLT_VLooseIsoPFTau140_Trk50_eta2p1_v
         */
        if ( not muon and singleTauTrigger and (e->IsTriggered("HLT_VLooseIsoPFTau120_Trk50_eta2p1_v") or e->IsTriggered("HLT_VLooseIsoPFTau140_Trk50_eta2p1_v")))  cut.SetCutBit(Trigger);
        else if (muon and e->IsTriggered("HLT_IsoMu20")) cut.SetCutBit(Trigger);
    }
    
    if (muon) { // special treatment for muons..
        
        if(e->IsTriggered("HLT_IsoMu20_v")) {
            cut.SetCutBit(Trigger);
            cout << "triggered" << endl;
        }
        else cout << "not triggered" << endl;
        
    }
    
    // --------------END TRIGGER

    if (t== NULL) return cut.raw();
    //if (sub != NULL) return cut.raw(); //multiple taus

    //----------------- ONE TAU -------------
    if (  // pt 20, Iso 1.5
            t->Pt()>= 50 and 
            fabs(t->Eta() ) <2.1
       ) cut.SetCutBit(OneTau) ;


    bool lepVeto=false;
    if (e->Nleps() ==0 ) lepVeto=true;
    else if( e->GetMuon(0) == NULL){ // no 10 GeV muon
        
        if (e->GetElectron(0) !=NULL and e->GetElectron(0)->Pt() <15) lepVeto=true; // pt ordered
    
    }

    if ( lepVeto and not muon) cut.SetCutBit(NoLep);
    if ( muon  and e->Nleps() ==1) cut.SetCutBit(NoLep);;

    // ---- At least 3 jets
    if ( direct and e->Njets() >=3 ) cut.SetCutBit(ThreeJets);
    if ( not direct and e->NjetsInvIso() >=3 ) cut.SetCutBit(ThreeJets);

    // --- At least 1 b-jet
    if ( direct and e->Bjets() >=1 ) cut.SetCutBit(OneBjet) ;
    if ( not direct and e->BjetsInvIso() >=1 ) cut.SetCutBit(OneBjet) ;

    
    // MET 
    if ( e->GetMet().Pt() >= 90 ) cut.SetCutBit(Met); // or PtUncorr

    double RbbMin= e->RbbMin(3,t);
    double RCollMin= e-> RCollMin(3,t);
    double RsrMax= e->RsrMax(3,t);

    //if ( RCollMin*TMath::RadToDeg() >40 ) cut.SetCutBit( AngColl) ;
    if ( RCollMin*TMath::RadToDeg() >= 0 ) cut.SetCutBit( AngColl) ;

    //if ( RbbMin*TMath::RadToDeg() >40 ) cut.SetCutBit(AngRbb) ;
    if ( RbbMin > 0.7 ) cut.SetCutBit(AngRbb) ;

    return cut.raw();
}