CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/TopQuarkAnalysis/TopHitFit/src/Top_Fit.cc

Go to the documentation of this file.
00001 //
00002 // $Id: Top_Fit.cc,v 1.1 2011/05/26 09:47:00 mseidel Exp $
00003 //
00004 // File: src/Top_Fit.cc
00005 // Purpose: Handle jet permutations.
00006 // Created: Jul, 2000, sss, based on run 1 mass analysis code.
00007 //
00008 // XXX handle merging jets.
00009 // XXX btagging for ttH.
00010 //
00011 // CMSSW File      : src/Top_Fit.cc
00012 // Original Author : Scott Stuart Snyder <snyder@bnl.gov> for D0
00013 // Imported to CMSSW by Haryo Sumowidagdo <Suharyo.Sumowidagdo@cern.ch>
00014 //
00015 
00016 
00041 #include "TopQuarkAnalysis/TopHitFit/interface/Top_Fit.h"
00042 #include "TopQuarkAnalysis/TopHitFit/interface/Lepjets_Event.h"
00043 #include "TopQuarkAnalysis/TopHitFit/interface/Top_Decaykin.h"
00044 #include "TopQuarkAnalysis/TopHitFit/interface/Defaults.h"
00045 #include "TopQuarkAnalysis/TopHitFit/interface/Fit_Results.h"
00046 #include "TopQuarkAnalysis/TopHitFit/interface/fourvec.h"
00047 #include <iostream>
00048 #include <algorithm>
00049 #include <cmath>
00050 #include <cassert>
00051 
00052 using std::cout;
00053 using std::endl;
00054 using std::abs;
00055 using std::next_permutation;
00056 using std::stable_sort;
00057 using std::vector;
00058 using std::ostream;
00059 
00060 
00061 namespace hitfit {
00062 
00063 
00064 //*************************************************************************
00065 // Argument handling.
00066 //
00067 
00068 
00069 Top_Fit_Args::Top_Fit_Args (const Defaults& defs)
00070 //
00071 // Purpose: Constructor.
00072 //
00073 // Inputs:
00074 //   defs -        The Defaults instance from which to initialize.
00075 //
00076   : _print_event_flag (defs.get_bool ("print_event_flag")),
00077     _do_higgs_flag (defs.get_bool ("do_higgs_flag")),
00078     _jet_mass_cut (defs.get_float ("jet_mass_cut")),
00079     _mwhad_min_cut (defs.get_float ("mwhad_min_cut")),
00080     _mwhad_max_cut (defs.get_float ("mwhad_max_cut")),
00081     _mtdiff_max_cut (defs.get_float ("mtdiff_max_cut")),
00082     _nkeep (defs.get_int ("nkeep")),
00083     _solve_nu_tmass (defs.get_bool ("solve_nu_tmass")),
00084     _args (defs)
00085    {
00086 }
00087 
00088 
00089 bool Top_Fit_Args::print_event_flag () const
00090 //
00091 // Purpose: Return the print_event_flag parameter.
00092 //          See the header for documentation.
00093 //
00094 {
00095   return _print_event_flag;
00096 }
00097 
00098 
00099 bool Top_Fit_Args::do_higgs_flag () const
00100 //
00101 // Purpose: Return the do_higgs_flag parameter.
00102 //          See the header for documentation.
00103 //
00104 {
00105   return _do_higgs_flag;
00106 }
00107 
00108 
00109 double Top_Fit_Args::jet_mass_cut () const
00110 //
00111 // Purpose: Return the jet_mass_cut parameter.
00112 //          See the header for documentation.
00113 //
00114 {
00115   return _jet_mass_cut;
00116 }
00117 
00118 
00119 double Top_Fit_Args::mwhad_min_cut () const
00120 //
00121 // Purpose: Return the mwhad_min_cut parameter.
00122 //          See the header for documentation.
00123 //
00124 {
00125   return _mwhad_min_cut;
00126 }
00127 
00128 
00129 double Top_Fit_Args::mwhad_max_cut () const
00130 //
00131 // Purpose: Return the mwhad_max_cut parameter.
00132 //          See the header for documentation.
00133 //
00134 {
00135   return _mwhad_max_cut;
00136 }
00137 
00138 
00139 double Top_Fit_Args::mtdiff_max_cut () const
00140 //
00141 // Purpose: Return the mtdiff_max_cut parameter.
00142 //          See the header for documentation.
00143 //
00144 {
00145   return _mtdiff_max_cut;
00146 }
00147 
00148 
00149 int Top_Fit_Args::nkeep () const
00150 //
00151 // Purpose: Return the nkeep parameter.
00152 //          See the header for documentation.
00153 //
00154 {
00155   return _nkeep;
00156 }
00157 
00158 
00159 bool Top_Fit_Args::solve_nu_tmass () const
00160 //
00161 // Purpose: Return the solve_nu_tmass parameter
00162 //          See the header for documentation.
00163 //
00164 {
00165   return _solve_nu_tmass;
00166 }
00167 
00168 
00169 const Constrained_Top_Args& Top_Fit_Args::constrainer_args () const
00170 //
00171 // Purpose: Return the contained subobject parameters.
00172 //
00173 {
00174   return _args;
00175 }
00176 
00177 
00178 
00179 //*************************************************************************
00180 // Helper functions.
00181 //
00182 
00183 
00184 namespace {
00185 
00186 
00201 bool test_for_bad_masses (const Lepjets_Event& ev,
00202                           const Top_Fit_Args& args,
00203                           double mwhad,
00204                           double umthad,
00205                           double umtlep)
00206 //
00207 // Purpose: Apply mass cuts to see if this event should be rejected
00208 //          without fitting.
00209 //
00210 // Inputs:
00211 //   ev -          The event to test.
00212 //   args -        Parameter setting.
00213 //   mwhad -       The hadronic W mass.
00214 //   umthad -      The hadronic top mass.
00215 //   umtlep -      The leptonic top mass.
00216 //
00217 // Returns:
00218 //   True if the event should be rejected.
00219 //
00220 {
00221 
00222   // Reject the event if any jet's mass is too large.
00223   if (ev.sum (lepb_label).m()  > args.jet_mass_cut() ||
00224       ev.sum (hadb_label).m()  > args.jet_mass_cut() ||
00225       ev.sum (hadw1_label).m() > args.jet_mass_cut() ||
00226       ev.sum (hadw2_label).m() > args.jet_mass_cut()) {
00227       return true;
00228   }
00229 
00230   // Reject if if the hadronic W mass is outside the window.
00231   if (mwhad < args.mwhad_min_cut()) {
00232       return true;
00233   }
00234 
00235   // Reject if if the hadronic W mass is outside the window.
00236   if (mwhad > args.mwhad_max_cut()) {
00237       return true;
00238   }
00239 
00240   // And if the two top masses are too far apart.
00241   if (abs (umthad - umtlep) > args.mtdiff_max_cut()) {
00242       return true;
00243   }
00244 
00245   // It's ok.
00246   return false;
00247 }
00248 
00249 
00259 vector<int> classify_jetperm (const vector<int>& jet_types,
00260                               const Lepjets_Event& ev)
00261 //
00262 // Purpose: Classify a jet permutation, to decide on what result
00263 //          lists it should be put.
00264 //
00265 // Inputs:
00266 //   jet_types -   Vector of jet types.
00267 //   ev -          The original event being fit.
00268 //
00269 // Returns:
00270 //   A list_flags vector, appropriate to pass to Fit_Results::push.
00271 //
00272 {
00273   // Start by assuming it's on all the lists.
00274   // We'll clear the flags if we see that it actually doesn't
00275   // belong.
00276   vector<int> out (n_lists);
00277   out[all_list] = 1;
00278   out[noperm_list] = 1;
00279   out[semicorrect_list] = 1;
00280   out[limited_isr_list] = 1;
00281   out[topfour_list] = 1;
00282   out[btag_list] = 1;
00283   out[htag_list] = 1;
00284 
00285   // Loop over jets.
00286   assert (jet_types.size() == ev.njets());
00287   for (vector<int>::size_type i=0; i < jet_types.size(); i++)
00288   {
00289     {
00290       int t1 =   jet_types[i];    // Current type of this jet.
00291       int t2 = ev.jet(i).type();  // `Correct' type of this jet.
00292 
00293       // Consider hadw1_label and hadw2_label the same.
00294       if (t1 == hadw2_label) t1 = hadw1_label;
00295       if (t2 == hadw2_label) t2 = hadw1_label;
00296 
00297       // If they're not the same, the permutation isn't correct.
00298       if (t1 != t2) out[noperm_list] = 0;
00299 
00300       // Test for a semicorrect permutation.
00301       // Here, all hadronic-side jets are considered equivalent.
00302       if (t1 == hadw1_label) t1 = hadb_label;
00303       if (t2 == hadw1_label) t2 = hadb_label;
00304       if (t1 != t2) out[semicorrect_list] = 0;
00305     }
00306 
00307     if (jet_types[i] == isr_label && i <= 2)
00308       out[limited_isr_list] = 0;
00309 
00310     if ((jet_types[i] == isr_label && i <= 3) ||
00311         (jet_types[i] != isr_label && i >= 4))
00312       out[topfour_list] = 0;
00313 
00314     if ((ev.jet(i).svx_tag() || ev.jet(i).slt_tag()) &&
00315         ! (jet_types[i] == hadb_label || jet_types[i] == lepb_label))
00316       out[btag_list] = 0;
00317 
00318     if ((ev.jet(i).svx_tag() || ev.jet(i).slt_tag()) &&
00319         ! (jet_types[i] == hadb_label  || jet_types[i] == lepb_label ||
00320            jet_types[i] == higgs_label))
00321       out[htag_list] = 0;
00322   }
00323   return out;
00324 }
00325 
00326 
00335 void set_jet_types (const vector<int>& jet_types,
00336                     Lepjets_Event& ev)
00337 //
00338 // Purpose: Update EV with a new set of jet types.
00339 //
00340 // Inputs:
00341 //   jet_types -   Vector of new jet types.
00342 //   ev -          The event to update.
00343 //
00344 // Outputs:
00345 //   ev -          The updated event.
00346 //
00347 {
00348   assert (ev.njets() == jet_types.size());
00349   bool saw_hadw1 = false;
00350   for (vector<int>::size_type i=0; i < ev.njets(); i++) {
00351     int t = jet_types[i];
00352     if (t == hadw1_label) {
00353       if (saw_hadw1)
00354         t = hadw2_label;
00355       saw_hadw1 = true;
00356     }
00357     ev.jet (i).type() = t;
00358   }
00359 }
00360 
00361 
00362 } // unnamed namespace
00363 
00364 
00365 //*************************************************************************
00366 
00367 
00368 Top_Fit::Top_Fit (const Top_Fit_Args& args,
00369                   double lepw_mass,
00370                   double hadw_mass,
00371                   double top_mass)
00372 //
00373 // Purpose: Constructor.
00374 //
00375 // Inputs:
00376 //   args -        The parameter settings for this instance.
00377 //   lepw_mass -   The mass to which the leptonic W should be constrained,
00378 //                 or 0 to skip this constraint.
00379 //   hadw_mass -   The mass to which the hadronic W should be constrained,
00380 //                 or 0 to skip this constraint.
00381 //   top_mass -    The mass to which the top quarks should be constrained,
00382 //                 or 0 to skip this constraint.
00383 //
00384   : _args (args),
00385     _constrainer (args.constrainer_args(),
00386                   lepw_mass, hadw_mass, top_mass),
00387     _lepw_mass(lepw_mass),
00388     _hadw_mass (hadw_mass)
00389 {
00390 }
00391 
00392 
00393 double Top_Fit::fit_one_perm (Lepjets_Event& ev,
00394                               bool& nuz,
00395                               double& umwhad,
00396                               double& utmass,
00397                               double& mt,
00398                               double& sigmt,
00399                               Column_Vector& pullx,
00400                               Column_Vector& pully)
00401 //
00402 // Purpose: Fit a single jet permutation.
00403 //
00404 // Inputs:
00405 //   ev -          The event to fit.
00406 //                 The object labels must have already been assigned.
00407 //   nuz -         Boolean flag to indicate which neutrino solution to be
00408 //                 used.
00409 //                 false = use smaller neutrino z solution
00410 //                 true  = use larger neutrino z solution
00411 //
00412 // Outputs:
00413 //   ev-           The event after the fit.
00414 //   umwhad -      Hadronic W mass before fitting.
00415 //   utmass -      Top mass before fitting, averaged from both sides.
00416 //   mt -          Top mass after fitting.
00417 //   sigmt -       Top mass uncertainty after fitting.
00418 //   pullx -       Vector of pull quantities for well-measured variables.
00419 //   pully -       Vector of pull quantities for poorly-measured variables.
00420 //
00421 // Returns:
00422 //   The fit chisq, or < 0 if the fit didn't converge.
00423 //
00424 // Adaptation note by Haryo Sumowidagdo:
00425 //   This function is rewritten in order to make its purpose reflects
00426 //   the function's name.  The function nows only fit one jet permutation
00427 //   with one neutrino solution only.
00428 //
00429 //
00430 {
00431   mt = 0;
00432   sigmt = 0;
00433 
00434   // Find the neutrino solutions by requiring either:
00435   // 1) that the leptonic top have the same mass as the hadronic top.
00436   // 2) that the mass of the lepton and neutrino is equal to the W mass
00437 
00438   umwhad = Top_Decaykin::hadw (ev) . m();
00439   double umthad = Top_Decaykin::hadt (ev) . m();
00440   double nuz1, nuz2;
00441 
00442   if (_args.solve_nu_tmass()) {
00443       Top_Decaykin::solve_nu_tmass (ev, umthad, nuz1, nuz2);
00444   }
00445   else {
00446       Top_Decaykin::solve_nu (ev, _lepw_mass, nuz1, nuz2);
00447   }
00448 
00449   // Set up to use the selected neutrino solution
00450   if (!nuz) {
00451       ev.met().setZ(nuz1);
00452   }
00453   else {
00454       ev.met().setZ(nuz2);
00455   }
00456 
00457   // Note: We have set the neutrino Pz, but we haven't set the neutrino energy.
00458   // Remember that originally the neutrino energy was equal to
00459   // sqrt(nu_px*nu_px + nu_py*nu_py).  Calculating the invariant mass squared
00460   // for the neutrino will give negative mass squared.
00461   // Therefore we need to adjust (increase) the neutrino energy in order to
00462   // make its mass remain zero.
00463 
00464   adjust_e_for_mass(ev.met(),0);
00465 
00466   // Find the unfit top mass as the average of the two sides.
00467   double umtlep = Top_Decaykin::lept (ev) . m();
00468   utmass = (umthad + umtlep) / 2;
00469 
00470   // Trace, if requested.
00471   if (_args.print_event_flag()) {
00472     cout << "Top_Fit::fit_one_perm() : Before fit:\n";
00473     Top_Decaykin::dump_ev (cout, ev);
00474   }
00475 
00476   // Maybe reject this event.
00477   if (_hadw_mass > 0 && test_for_bad_masses (ev, _args, umwhad,
00478                                              umthad, umtlep))
00479   {
00480     cout << "Top_Fit: bad mass comb.\n";
00481     return -999;
00482   }
00483 
00484   // Do the fit.
00485   double chisq = _constrainer.constrain (ev, mt, sigmt, pullx, pully);
00486 
00487   // Trace, if requested.
00488   if (_args.print_event_flag()) {
00489     cout << "Top_Fit::fit_one_perm() : After fit:\n";
00490     cout << "chisq: " << chisq << " mt: " << mt << " ";
00491     Top_Decaykin::dump_ev (cout, ev);
00492   }
00493 
00494   // Done!
00495   return chisq;
00496 }
00497 
00498 
00499 Fit_Results Top_Fit::fit (const Lepjets_Event& ev)
00500 //
00501 // Purpose: Fit all jet permutations for EV.
00502 //
00503 // Inputs:
00504 //   ev -          The event to fit.
00505 //
00506 // Returns:
00507 //   The results of the fit.
00508 //
00509 {
00510   // Make a new Fit_Results object.
00511   Fit_Results res (_args.nkeep(), n_lists);
00512 
00513   // Set up the vector of jet types.
00514   vector<int> jet_types (ev.njets(), isr_label);
00515   assert (ev.njets() >= 4);
00516   jet_types[0] = lepb_label;
00517   jet_types[1] = hadb_label;
00518   jet_types[2] = hadw1_label;
00519   jet_types[3] = hadw1_label;
00520 
00521   if (_args.do_higgs_flag() && ev.njets() >= 6) {
00522     jet_types[4] = higgs_label;
00523     jet_types[5] = higgs_label;
00524   }
00525 
00526   // Must be in sorted order.
00527   stable_sort (jet_types.begin(), jet_types.end());
00528 
00529   do {
00530 
00531     // Loop over the two possible neutrino solution
00532     for (int nusol = 0 ; nusol != 2 ; nusol++) {
00533 
00534     // Set up the neutrino solution to be used
00535     bool nuz = bool(nusol);
00536 
00537     // Copy the event.
00538     Lepjets_Event fev = ev;
00539 
00540     // Install the new jet types.
00541     set_jet_types (jet_types, fev);
00542 
00543     // Figure out on what lists this permutation should go.
00544     vector<int> list_flags = classify_jetperm (jet_types, ev);
00545 
00546     // Set up the output variables for fit results.
00547     double umwhad, utmass, mt, sigmt;
00548     Column_Vector pullx;
00549     Column_Vector pully;
00550     double chisq;
00551 
00552     // Tracing.
00553     cout << "Top_Fit::fit(): Before fit: (";
00554     for (vector<int>::size_type i=0; i < jet_types.size(); i++) {
00555         if (i) cout << " ";
00556         cout << jet_types[i];
00557     }
00558     cout << " nuz = " << nuz ;
00559     cout << ") " << std::endl;
00560 
00561     // Do the fit.
00562     chisq = fit_one_perm (fev, nuz, umwhad, utmass, mt, sigmt, pullx, pully);
00563 
00564     // Print the result, if requested.
00565     if (_args.print_event_flag()) {
00566         cout << "Top_Fit::fit(): After fit:\n";
00567         char buf[256];
00568         sprintf (buf, "chisq: %8.3f  mt: %6.2f pm %5.2f %c\n",
00569              chisq, mt, sigmt, (list_flags[noperm_list] ? '*' : ' '));
00570         cout << buf;
00571     }
00572 
00573     // Add it to the results.
00574     res.push (chisq, fev, pullx, pully, umwhad, utmass, mt, sigmt, list_flags);
00575 
00576     } // end of for loop over the two neutrino solution
00577 
00578     // Step to the next permutation.
00579   } while (next_permutation (jet_types.begin(), jet_types.end()));
00580 
00581   return res;
00582 }
00583 
00584 
00593 std::ostream& operator<< (std::ostream& s, const Top_Fit& fitter)
00594 //
00595 // Purpose: Print the object to S.
00596 //
00597 // Inputs:
00598 //   s -           The stream to which to write.
00599 //   fitter -      The object to write.
00600 //
00601 // Returns:
00602 //   The stream S.
00603 //
00604 {
00605   return s << fitter._constrainer;
00606 }
00607 
00608 
00609 const Top_Fit_Args& Top_Fit::args() const
00610 {
00611     return _args;
00612 }
00613 
00614 } // namespace hitfit