CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Fourvec_Constrainer.cc
Go to the documentation of this file.
1 //
2 // $Id: Fourvec_Constrainer.cc,v 1.2 2012/11/21 19:07:26 davidlt Exp $
3 //
4 // File: src/Fourvec_Constrainer.cc
5 // Purpose: Do a kinematic fit for a set of 4-vectors, given a set
6 // of mass constraints.
7 // Created: Jul, 2000, sss, based on run 1 mass analysis code.
8 //
9 // CMSSW File : src/Fourvec_Constrainer.cc
10 // Original Author : Scott Stuart Snyder <snyder@bnl.gov> for D0
11 // Imported to CMSSW by Haryo Sumowidagdo <Suharyo.Sumowidagdo@cern.ch>
12 //
13 
14 
47 #include <cmath>
48 #include <iostream>
49 
50 
51 using std::sqrt;
52 using std::exp;
53 using std::cos;
54 using std::sin;
55 using std::ostream;
56 using std::vector;
57 
58 
59 namespace hitfit {
60 
61 
62 //*************************************************************************
63 // Argument handling.
64 //
65 
66 
68 //
69 // Purpose: Constructor.
70 //
71 // Inputs:
72 // defs - The Defaults instance from which to initialize.
73 //
74  : _use_e (defs.get_bool ("use_e")),
75  _e_com (defs.get_float ("e_com")),
76  _ignore_met (defs.get_bool ("ignore_met")),
77  _chisq_constrainer_args (defs)
78 {
79 }
80 
81 
83 //
84 // Purpose: Return the use_e parameter.
85 // See the header for documentation.
86 //
87 {
88  return _use_e;
89 }
90 
91 
93 //
94 // Purpose: Return the e_com parameter.
95 // See the header for documentation.
96 //
97 {
98  return _e_com;
99 }
100 
101 
103 //
104 // Purpose: Return the ignore_met parameter.
105 // See the header for documentation.
106 //
107 {
108  return _ignore_met;
109 }
110 
111 
114 //
115 // Purpose: Return the contained subobject parameters.
116 //
117 {
119 }
120 
121 
122 //*************************************************************************
123 // Variable layout.
124 //
125 // We need to map the quantities we fit onto the vectors of well- and
126 // poorly-measured quantities.
127 //
128 
129 //
130 // The well-measured variables consist of three variables for each
131 // object. If we are using transverse momentum constraints,
132 // these fill be followed by the two cartesian components of kt.
133 //
134 // Each object is represented by three variables: the momentum (or 1/p
135 // if the muon flag was set), and the two spherical angles, phi and eta.
136 // Here is how they're ordered.
137 //
141 typedef enum {
142  p_offs = 0,
143  phi_offs = 1,
145 } Offsets;
146 
151 typedef enum {
152  x_offs = 0,
153  y_offs = 1
154 } Kt_Offsets;
155 
156 //
157 // If there is a neutrino, then it is at index 1 of the poorly-measured
158 // set (otherwise, that set is empty).
159 //
164 typedef enum {
165  nu_z = 1
167 
168 
169 
170 namespace {
171 
172 
179 int obj_index (int i)
180 //
181 // Purpose: Return the starting variable index for object I.
182 //
183 // Inputs:
184 // i - The object index.
185 //
186 // Returns:
187 // The index in the well-measured set of the first variable
188 // for object I.
189 //
190 {
191  return i*3 + 1;
192 }
193 
194 
195 } // unnamed namespace
196 
197 
198 //*************************************************************************
199 // Object management.
200 //
201 
202 
204 //
205 // Purpose: Constructor.
206 //
207 // Inputs:
208 // args - The parameter settings for this instance.
209 //
210  : _args (args)
211 {
212 }
213 
214 
216 //
217 // Purpose: Specify an additional constraint S for the problem.
218 // The format for S is described in the header.
219 //
220 // Inputs:
221 // s - The constraint to add.
222 //
223 {
224  _constraints.push_back (Constraint (s));
225 }
226 
227 
229 //
230 // Purpose: Specify the combination of objects that will be returned by
231 // constrain() as the mass. The format of S is the same as for
232 // normal constraints. The LHS specifies the mass to calculate;
233 // the RHS should be zero.
234 // This should only be called once.
235 //
236 // Inputs:
237 // s - The constraint defining the mass.
238 //
239 {
240  assert (_mass_constraint.size() == 0);
241  _mass_constraint.push_back (Constraint (s));
242 }
243 
244 
254 std::ostream& operator<< (std::ostream& s, const Fourvec_Constrainer& c)
255 //
256 // Purpose: Print the object to S.
257 //
258 // Inputs:
259 // s - The stream to which to write.
260 // c - The object to write.
261 //
262 // Returns:
263 // The stream S.
264 //
265 {
266  s << "Constraints: (e_com = " << c._args.e_com() << ") ";
267  if (c._args.use_e())
268  s << "(E)";
269  s << "\n";
270 
271  for (std::vector<Constraint>::size_type i=0; i < c._constraints.size(); i++)
272  s << " " << c._constraints[i] << "\n";
273 
274  if (c._mass_constraint.size() > 0) {
275  s << "Mass constraint:\n";
276  s << c._mass_constraint[0] << "\n";
277  }
278  return s;
279 }
280 
281 
282 //*************************************************************************
283 // Event packing and unpacking.
284 //
285 
286 
287 namespace {
288 
289 
300 void adjust_fourvecs (Fourvec_Event& ev,
301  bool use_e_flag)
302 //
303 // Purpose: For all objects in EV, adjust their 4-momenta
304 // to have their requested masses.
305 //
306 // Inputs:
307 // ev - The event on which to operate.
308 // use_e_flag - If true, keep E and scale 3-momentum.
309 // If false, keep the 3-momentum and scale E.
310 //
311 {
312  int nobjs = ev.nobjs ();
313  for (int i=0; i < nobjs; i++) {
314  const FE_Obj& obj = ev.obj (i);
315  Fourvec p = obj.p;
316  if (use_e_flag)
317  adjust_p_for_mass (p, obj.mass);
318  else
319  adjust_e_for_mass (p, obj.mass);
320  ev.set_obj_p (i, p);
321  }
322 }
323 
324 
341 Fourvec get_p_eta_phi_vec (const Column_Vector& c,
342  int ndx,
343  const FE_Obj& obj,
344  bool use_e_flag)
345 //
346 // Purpose: Convert object NDX from its representation in the set
347 // of well-measured variables C to a 4-vector.
348 //
349 // Inputs:
350 // c - The vector of well-measured variables.
351 // ndx - The index of the object in which we're interested.
352 // obj - The object from the Fourvec_Event.
353 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
354 //
355 // Returns:
356 // The object's 4-momentum.
357 //
358 {
359  // Get the energy and momentum of the object.
360  double e, p;
361 
362  if (use_e_flag) {
363  // We're using E as a fit variable. Get it directly.
364  e = c(ndx + p_offs);
365 
366  // Take into account the muon case.
367  if (obj.muon_p) e = 1/e;
368 
369  // Find the momentum given the energy.
370  if (obj.mass == 0)
371  p = e;
372  else {
373  double xx = e*e - obj.mass*obj.mass;
374  if (xx >= 0)
375  p = sqrt (xx);
376  else
377  p = 0;
378  }
379  }
380  else {
381  // We're using P as a fit variable. Fetch it.
382  p = c(ndx + p_offs);
383 
384  // Take into account the muon case.
385  if (obj.muon_p) p = 1/p;
386 
387  // Find the energy given the momentum.
388  e = (obj.mass == 0 ? p : sqrt (obj.mass*obj.mass + p*p));
389  }
390 
391  // Get angular variables.
392  double phi = c(ndx + phi_offs);
393  double eta = c(ndx + eta_offs);
394  if (fabs (eta) > 50) {
395  // Protect against ridiculously large etas
396  eta = eta > 0 ? 50 : -50;
397  }
398  double exp_eta = exp (eta);
399  double iexp_eta = 1/exp_eta;
400  double sin_theta = 2 / (exp_eta + iexp_eta);
401  double cos_theta = (exp_eta - iexp_eta) / (exp_eta + iexp_eta);
402 
403  // Form the 4-momentum.
404  return Fourvec (p * sin_theta * cos (phi),
405  p * sin_theta * sin (phi),
406  p * cos_theta,
407  e);
408 }
409 
410 
427 void set_p_eta_phi_vec (const FE_Obj& obj,
428  Column_Vector& c,
429  int ndx,
430  bool use_e_flag)
431 //
432 // Purpose: Initialize the variables in the well-measured set C describing
433 // object NDX from its Fourvec_Event representation OBJ.
434 //
435 // Inputs:
436 // obj - The object from the Fourvec_Event.
437 // c - The vector of well-measured variables.
438 // ndx - The index of the object in which we're interested.
439 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
440 //
441 //
442 {
443  if (use_e_flag)
444  c(ndx + p_offs) = obj.p.e();
445  else
446  c(ndx + p_offs) = obj.p.vect().mag();
447 
448  if (obj.muon_p) c(ndx + p_offs) = 1/c(ndx + p_offs);
449  c(ndx + phi_offs) = obj.p.phi();
450  c(ndx + eta_offs) = obj.p.pseudoRapidity();
451 }
452 
453 
463 Matrix error_matrix (double p_sig,
464  double phi_sig,
465  double eta_sig)
466 //
467 // Purpose: Set up the 3x3 error matrix for an object.
468 //
469 // Inputs:
470 // p_sig - The momentum uncertainty.
471 // phi_sig - The phi uncertainty.
472 // eta_sig - The eta uncertainty.
473 //
474 // Returns:
475 // The object's error matrix.
476 //
477 {
478  Matrix err (3, 3, 0);
479  err(1+ p_offs, 1+ p_offs) = p_sig * p_sig;
480  err(1+phi_offs, 1+phi_offs) = phi_sig * phi_sig;
481  err(1+eta_offs, 1+eta_offs) = eta_sig * eta_sig;
482  return err;
483 }
484 
485 
511 void pack_event (const Fourvec_Event& ev,
512  bool use_e_flag,
513  bool use_kt_flag,
514  Column_Vector& xm,
515  Column_Vector& ym,
516  Matrix& G_i,
517  Diagonal_Matrix& Y)
518 //
519 // Purpose: Take the information from a Fourvec_Event EV and pack
520 // it into vectors of well- and poorly-measured variables.
521 // Also set up the error matrices.
522 //
523 // Inputs:
524 // ev - The event to pack.
525 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
526 // use_kt_flag - True if we're to pack kt variables.
527 //
528 // Outputs:
529 // xm - Vector of well-measured variables.
530 // ym - Vector of poorly-measured variables.
531 // G_i - Error matrix for well-measured variables.
532 // Y - Inverse error matrix for poorly-measured variables.
533 //
534 {
535  // Number of objects in the event.
536  int nobjs = ev.nobjs ();
537 
538  int n_measured_vars = nobjs * 3;
539  if (use_kt_flag)
540  n_measured_vars += 2;
541 
542  // Clear the error matrix.
543  G_i = Matrix (n_measured_vars, n_measured_vars, 0);
544 
545  // Loop over objects.
546  for (int i=0; i<nobjs; i++) {
547  const FE_Obj& obj = ev.obj (i);
548  int this_index = obj_index (i);
549  set_p_eta_phi_vec (obj, xm, this_index, use_e_flag);
550  G_i.sub (this_index, this_index, error_matrix (obj.p_error,
551  obj.phi_error,
552  obj.eta_error));
553 
554  }
555 
556  if (use_kt_flag) {
557  // Set up kt.
558  int kt_ndx = obj_index (nobjs);
559  xm (kt_ndx+x_offs) = ev.kt().x();
560  xm (kt_ndx+y_offs) = ev.kt().y();
561 
562  // And its error matrix.
563  G_i(kt_ndx+x_offs, kt_ndx+x_offs) = ev.kt_x_error() * ev.kt_x_error();
564  G_i(kt_ndx+y_offs, kt_ndx+y_offs) = ev.kt_y_error() * ev.kt_y_error();
565  G_i(kt_ndx+x_offs, kt_ndx+y_offs) = ev.kt_xy_covar();
566  G_i(kt_ndx+y_offs, kt_ndx+x_offs) = ev.kt_xy_covar();
567  }
568 
569  // Handle a neutrino.
570  if (ev.has_neutrino()) {
571  ym(nu_z) = ev.nu().z();
572  Y = Diagonal_Matrix (1, 0);
573  }
574 }
575 
576 
596 void unpack_event (Fourvec_Event& ev,
597  const Column_Vector& x,
598  const Column_Vector& y,
599  bool use_e_flag,
600  bool use_kt_flag)
601 //
602 // Purpose: Update the contents of EV from the variable sets X and Y.
603 //
604 // Inputs:
605 // ev - The event.
606 // x - Vector of well-measured variables.
607 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
608 // use_kt_flag - True if we're too unpack kt variables.
609 //
610 // Outputs:
611 // ev - The event after updating.
612 //
613 {
614  // Do all the objects.
615  Fourvec sum = Fourvec(0);
616  for (int j=0; j<ev.nobjs(); j++) {
617  const FE_Obj& obj = ev.obj (j);
618  ev.set_obj_p (j, get_p_eta_phi_vec (x, obj_index (j), obj, use_e_flag));
619  sum += obj.p;
620  }
621 
622 
623  if (use_kt_flag) {
624  int kt_ndx = obj_index (ev.nobjs());
625  Fourvec kt = Fourvec (x(kt_ndx+x_offs), x(kt_ndx+y_offs), 0, 0);
626  Fourvec nu = kt - sum;
627  if (ev.has_neutrino()) {
628  nu.setPz (y(nu_z));
629  adjust_e_for_mass (nu, 0);
630  ev.set_nu_p (nu);
631  }
632  else {
633  adjust_e_for_mass (nu, 0);
634  ev.set_x_p (nu);
635  }
636  }
637 }
638 
639 
640 } // unnamed namespace
641 
642 
643 //*************************************************************************
644 // Constraint evaluation.
645 //
646 
647 
648 namespace {
649 
650 
679 double dot_and_gradient (const Fourvec& v1,
680  const Fourvec& v2,
681  bool use_e_flag,
682  double v1_x[3],
683  double v2_x[3],
684  bool& badflag)
685 //
686 // Purpose: Compute the dot product v1.v2 and its gradients wrt
687 // p, phi, and theta of each 4-vector.
688 //
689 // Inputs:
690 // v1 - The first 4-vector in the dot product.
691 // v2 - The second 4-vector in the dot product.
692 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
693 //
694 // Outputs:
695 // v1_x - Gradients of the dot product wrt v1's p, phi, theta.
696 // v2_x - Gradients of the dot product wrt v2's p, phi, theta.
697 // badflag - Set to true for the singular case (vectors vanish).
698 //
699 // Returns:
700 // The dot product.
701 //
702 {
703  // Calculate the dot product.
704  double dot = v1 * v2;
705 
706  double p1 = v1.vect().mag();
707  double p2 = v2.vect().mag();
708  double e1 = v1.e();
709  double e2 = v2.e();
710  double pt1 = v1.vect().perp();
711  double pt2 = v2.vect().perp();
712 
713  // Protect against the singular case.
714  badflag = false;
715  if (p1 == 0 || p2 == 0 || e1 == 0 || e2 == 0 || pt1 == 0 || pt2 == 0) {
716  badflag = true;
717  v1_x[p_offs] = v1_x[phi_offs] = v1_x[eta_offs] = 0;
718  v2_x[p_offs] = v2_x[phi_offs] = v2_x[eta_offs] = 0;
719  return false;
720  }
721 
722  // Calculate the gradients.
723  v1_x[p_offs] = (dot - v1.m2() * e2 / e1) / p1;
724  v2_x[p_offs] = (dot - v2.m2() * e1 / e2) / p2;
725 
726  if (use_e_flag) {
727  v1_x[p_offs] *= e1 / p1;
728  v2_x[p_offs] *= e2 / p2;
729  }
730 
731  v1_x[phi_offs] = v1(1)*v2(0) - v1(0)*v2(1);
732  v2_x[phi_offs] = -v1_x[phi_offs];
733 
734  double fac = v1(0)*v2(0) + v1(1)*v2(1);
735  v1_x[eta_offs] = pt1*v2(2) - v1(2)/pt1 * fac;
736  v2_x[eta_offs] = pt2*v1(2) - v2(2)/pt2 * fac;
737 
738  return dot;
739 }
740 
741 
763 void addin_obj_gradient (int constraint_no,
764  int sign,
765  int base_index,
766  const double grad[],
767  Matrix& Bx)
768 //
769 // Purpose: Tally up the dot product gradients for an object
770 // into Bx.
771 //
772 // Inputs:
773 // constraint_no-The number of the constraint.
774 // base_index - The index in the well-measured variable list
775 // of the first variable for this object.
776 // sign - The sign with which these gradients should be
777 // added into Bx, either +1 or -1. (I.e., which
778 // side of the constraint equation.)
779 // grad - The gradients for this object, vs. p, phi, theta.
780 // Bx - The well-measured variable gradients.
781 //
782 // Outputs:
783 // Bx - The well-measured variable gradients, updated.
784 //
785 {
786  Bx(base_index + p_offs, constraint_no) += sign * grad[p_offs];
787  Bx(base_index + phi_offs, constraint_no) += sign * grad[phi_offs];
788  Bx(base_index + eta_offs, constraint_no) += sign * grad[eta_offs];
789 }
790 
791 
819 void addin_nu_gradient (int constraint_no,
820  int sign,
821  int kt_ndx,
822  const double grad[],
823  Matrix& Bx, Matrix& By)
824 //
825 // Purpose: Tally up the dot product gradients for a neutrino
826 // into Bx and By.
827 //
828 // Inputs:
829 // constraint_no-The number of the constraint.
830 // sign - The sign with which these gradients should be
831 // added into Bx, either +1 or -1. (I.e., which
832 // side of the constraint equation.)
833 // kt_ndx - The index of the kt variables in the variables array.
834 // grad - The gradients for this object, vs. p, phi, theta.
835 // Bx - The well-measured variable gradients.
836 // By - The poorly-measured variable gradients.
837 //
838 // Outputs:
839 // Bx - The well-measured variable gradients, updated.
840 // By - The poorly-measured variable gradients, updated.
841 //
842 {
843  Bx(kt_ndx+x_offs,constraint_no) += sign*grad[p_offs]; // Really p for now.
844  Bx(kt_ndx+y_offs,constraint_no) += sign*grad[phi_offs];// Really phi for now.
845  By(nu_z, constraint_no) += sign*grad[eta_offs]; // Really theta ...
846 }
847 
848 
875 void addin_gradient (const Fourvec_Event& ev,
876  int constraint_no,
877  int sign,
878  int obj_no,
879  const double grad[],
880  Matrix& Bx,
881  Matrix& By)
882 //
883 // Purpose: Tally up the dot product gradients for an object (which may
884 // or may not be a neutrino) into Bx and By.
885 //
886 // Inputs:
887 // ev - The event we're fitting.
888 // constraint_no-The number of the constraint.
889 // sign - The sign with which these gradients should be
890 // added into Bx, either +1 or -1. (I.e., which
891 // side of the constraint equation.)
892 // obj_no - The number of the object.
893 // grad - The gradients for this object, vs. p, phi, theta.
894 // Bx - The well-measured variable gradients.
895 // By - The poorly-measured variable gradients.
896 //
897 // Outputs:
898 // Bx - The well-measured variable gradients, updated.
899 // By - The poorly-measured variable gradients, updated.
900 //
901 {
902  if (obj_no >= ev.nobjs()) {
903  assert (obj_no == ev.nobjs());
904  addin_nu_gradient (constraint_no, sign, obj_index (obj_no), grad, Bx, By);
905  }
906  else
907  addin_obj_gradient (constraint_no, sign, obj_index (obj_no), grad, Bx);
908 }
909 
910 
941 void addin_gradients (const Fourvec_Event& ev,
942  int constraint_no,
943  int sign,
944  int i,
945  const double igrad[],
946  int j,
947  const double jgrad[],
948  Matrix& Bx,
949  Matrix& By)
950 //
951 // Purpose: Tally up the gradients from a single dot product into Bx and By.
952 //
953 // Inputs:
954 // ev - The event we're fitting.
955 // constraint_no-The number of the constraint.
956 // sign - The sign with which these gradients should be
957 // added into Bx, either +1 or -1. (I.e., which
958 // side of the constraint equation.)
959 // i - The number of the first object.
960 // igrad - The gradients for the first object, vs. p, phi, theta.
961 // j - The number of the second object.
962 // jgrad - The gradients for the second object, vs. p, phi, theta.
963 // Bx - The well-measured variable gradients.
964 // By - The poorly-measured variable gradients.
965 //
966 // Outputs:
967 // Bx - The well-measured variable gradients, updated.
968 // By - The poorly-measured variable gradients, updated.
969 //
970 {
971  addin_gradient (ev, constraint_no, sign, i, igrad, Bx, By);
972  addin_gradient (ev, constraint_no, sign, j, jgrad, Bx, By);
973 }
974 
975 
988 void add_mass_terms (const Fourvec_Event& ev,
989  const vector<Constraint>& constraints,
990  Row_Vector& F)
991 //
992 // Purpose: Add the m^2 terms into the constraint values.
993 //
994 // Inputs:
995 // ev - The event we're fitting.
996 // constraints - The list of constraints.
997 // F - Vector of constraint values.
998 //
999 // Outputs:
1000 // F - Vector of constraint values, updated.
1001 //
1002 {
1003  for (std::vector<Constraint>::size_type i=0; i<constraints.size(); i++)
1004  F(i+1) += constraints[i].sum_mass_terms (ev);
1005 }
1006 
1007 
1041 bool calculate_mass_constraints (const Fourvec_Event& ev,
1042  const Pair_Table& pt,
1043  const vector<Constraint>& constraints,
1044  bool use_e_flag,
1045  Row_Vector& F,
1046  Matrix& Bx,
1047  Matrix& By)
1048 //
1049 // Purpose: Calculate the mass constraints and gradients.
1050 // Note: At this stage, the gradients are calculated not
1051 // quite with respect to the fit variables; instead, for
1052 // all objects (including the neutrino) we calculate
1053 // the gradients with respect to p, phi, theta. They'll
1054 // be converted via appropriate Jacobian transformations
1055 // later.
1056 //
1057 // Inputs:
1058 // ev - The event we're fitting.
1059 // pt - Table of cached pair assignments.
1060 // constraints - The list of constraints.
1061 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1062 //
1063 // Outputs:
1064 // (nb. these should be passed in correctly dimensioned.)
1065 // F - Vector of constraint values.
1066 // Bx - The well-measured variable gradients.
1067 // By - The poorly-measured variable gradients.
1068 //
1069 {
1070  int npairs = pt.npairs ();
1071  for (int p=0; p < npairs; p++) {
1072  const Objpair& objpair = pt.get_pair (p);
1073  int i = objpair.i();
1074  int j = objpair.j();
1075  double igrad[3], jgrad[3];
1076  bool badflag = false;
1077  double dot = dot_and_gradient (ev.obj (i).p,
1078  ev.obj (j).p,
1079  use_e_flag,
1080  igrad,
1081  jgrad,
1082  badflag);
1083  if (badflag)
1084  return false;
1085 
1086  for (std::vector<Constraint>::size_type k=0; k < constraints.size(); k++)
1087  if (objpair.for_constraint (k)) {
1088  F(k+1) += objpair.for_constraint (k) * dot;
1089  addin_gradients (ev, k+1, objpair.for_constraint (k),
1090  i, igrad, j, jgrad, Bx, By);
1091  }
1092 
1093  }
1094 
1095  add_mass_terms (ev, constraints, F);
1096  return true;
1097 }
1098 
1099 
1122 void add_nuterm (unsigned ndx,
1123  const Fourvec& v,
1124  Matrix& Bx,
1125  bool use_e_flag,
1126  int kt_ndx)
1127 //
1128 // Purpose: Carry out the Jacobian transformation for
1129 // (p_nu^x,p_nu_y) -> (kt^x, kt_y) for a given object.
1130 //
1131 // Inputs:
1132 // ndx - Index of the object for which to transform gradients.
1133 // v - The object's 4-momentum.
1134 // Bx - The well-measured variable gradients.
1135 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1136 // kt_ndx - The index of the kt variables in the variables array.
1137 //
1138 // Outputs:
1139 // Bx - The well-measured variable gradients, updated.
1140 //
1141 {
1142  double px = v.px();
1143  double py = v.py();
1144  double cot_theta = v.pz() / v.vect().perp();
1145 
1146  for (int j=1; j<=Bx.num_col(); j++) {
1147  double dxnu = Bx(kt_ndx+x_offs, j);
1148  double dynu = Bx(kt_ndx+y_offs, j);
1149 
1150  if (dxnu != 0 || dynu != 0) {
1151  double fac = 1 / v.vect().mag();
1152  if (use_e_flag)
1153  fac = v.e() * fac * fac;
1154  Bx(ndx + p_offs, j) -= (px*dxnu + py*dynu) * fac;
1155  Bx(ndx + phi_offs, j) += py*dxnu - px*dynu;
1156  Bx(ndx + eta_offs, j) -= (px*dxnu + py*dynu) * cot_theta;
1157  }
1158  }
1159 }
1160 
1161 
1185 void convert_neutrino (const Fourvec_Event& ev,
1186  bool use_e_flag,
1187  Matrix& Bx,
1188  Matrix& By)
1189 //
1190 // Purpose: Carry out the Jacobian transformations the neutrino.
1191 // First, convert from spherical (p, phi, theta) coordinates
1192 // to rectangular (x, y, z). Then convert from neutrino pt
1193 // components to kt components.
1194 //
1195 // Inputs:
1196 // ev - The event we're fitting.
1197 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1198 // Bx - The well-measured variable gradients.
1199 // By - The poorly-measured variable gradients.
1200 //
1201 // Outputs:
1202 // Bx - The well-measured variable gradients, updated.
1203 // By - The poorly-measured variable gradients, updated.
1204 //
1205 {
1206  int nconstraints = Bx.num_col ();
1207 
1208  const Fourvec& nu = ev.nu ();
1209 
1210  // convert neutrino from polar coordinates to rectangular.
1211  double pnu2 = nu.vect().mag2(); double pnu = sqrt (pnu2);
1212  double ptnu2 = nu.vect().perp2(); double ptnu = sqrt (ptnu2);
1213 
1214  // Doesn't matter whether we use E or P here, since nu is massless.
1215 
1216  double thfac = nu.z()/pnu2/ptnu;
1217  double fac[3][3];
1218  fac[0][0] = nu(0)/pnu; fac[0][1] = nu(1)/pnu; fac[0][2] = nu(2)/pnu;
1219  fac[1][0] = - nu(1)/ptnu2; fac[1][1] = nu(0)/ptnu2; fac[1][2] = 0;
1220  fac[2][0] = nu(0)*thfac; fac[2][1] = nu(1)*thfac; fac[2][2] = -ptnu/pnu2;
1221 
1222  int kt_ndx = obj_index (ev.nobjs());
1223  for (int j=1; j<=nconstraints; j++) {
1224  double tmp1 = fac[0][0]*Bx(kt_ndx+x_offs,j) +
1225  fac[1][0]*Bx(kt_ndx+y_offs,j) +
1226  fac[2][0]*By(nu_z,j);
1227  Bx(kt_ndx+y_offs,j) = fac[0][1]*Bx(kt_ndx+x_offs,j) +
1228  fac[1][1]*Bx(kt_ndx+y_offs,j) +
1229  fac[2][1]*By(nu_z,j);
1230  By(nu_z,j) = fac[0][2]*Bx(kt_ndx+x_offs,j) + fac[2][2]*By(nu_z,j);
1231 
1232  Bx(kt_ndx+x_offs,j) = tmp1;
1233  }
1234 
1235  // Add nu terms.
1236  for (int j=0; j<ev.nobjs(); j++) {
1237  add_nuterm (obj_index (j), ev.obj(j).p, Bx, use_e_flag, kt_ndx);
1238  }
1239 }
1240 
1241 
1262 void calculate_kt_constraints (const Fourvec_Event& ev,
1263  bool use_e_flag,
1264  Row_Vector& F,
1265  Matrix& Bx)
1266 //
1267 // Purpose: Calculate the overall kt constraints (kt = 0) for the case
1268 // where there is no neutrino.
1269 //
1270 // Inputs:
1271 // ev - The event we're fitting.
1272 // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1273 // F - Vector of constraint values.
1274 // Bx - The well-measured variable gradients.
1275 //
1276 // Outputs:
1277 // F - Vector of constraint values, updated.
1278 // Bx - The well-measured variable gradients, updated.
1279 //
1280 {
1281  Fourvec tmp = Fourvec(0);
1282  int base = F.num_col() - 2;
1283  int nobjs = ev.nobjs();
1284  for (int j=0; j<nobjs; j++) {
1285  const Fourvec& obj = ev.obj (j).p;
1286  tmp += obj;
1287 
1288  int ndx = obj_index (j);
1289  double p = obj.vect().mag();
1290  double cot_theta = obj.z() / obj.vect().perp();
1291 
1292  Bx(ndx + p_offs, base+1) = obj(0) / p;
1293  Bx(ndx + phi_offs, base+1) = -obj(1);
1294  Bx(ndx + eta_offs, base+1) = obj(0) * cot_theta;
1295 
1296  Bx(ndx + p_offs, base+2) = obj(1) / p;
1297  Bx(ndx + phi_offs, base+2) = obj(0);
1298  Bx(ndx + eta_offs, base+2) = obj(1) * cot_theta;
1299 
1300  if (use_e_flag) {
1301  Bx(ndx + p_offs, base+1) *= obj.e() / p;
1302  Bx(ndx + p_offs, base+2) *= obj.e() / p;
1303  }
1304  }
1305 
1306  int kt_ndx = obj_index (nobjs);
1307  Bx(kt_ndx+x_offs, base+1) = -1;
1308  Bx(kt_ndx+y_offs, base+2) = -1;
1309 
1310  F(base+1) = tmp(0) - ev.kt().x ();
1311  F(base+2) = tmp(1) - ev.kt().y ();
1312 }
1313 
1314 
1328 void ddtheta_to_ddeta (int i, double cos_theta, Matrix& Bx)
1329 //
1330 // Purpose: Do the Jacobian transformation from theta -> eta
1331 // for a single object.
1332 //
1333 // Inputs:
1334 // i - The index of the object.
1335 // cos_theta - cos(theta) for the object.
1336 // Bx - The well-measured variable gradients.
1337 //
1338 // Outputs:
1339 // Bx - The well-measured variable gradients, updated.
1340 //
1341 {
1342  double sin_theta = sqrt (1 - cos_theta * cos_theta);
1343  for (int j=1; j<=Bx.num_col(); j++)
1344  Bx(i,j) *= - sin_theta; /* \sin\theta = 1 / \cosh\eta */
1345 }
1346 
1347 
1348 } // unnamed namespace
1349 
1350 
1377  : public Constraint_Calculator
1378 //
1379 // Purpose: Constraint evaluator.
1380 //
1381 {
1382 public:
1383  // Constructor, destructor.
1385  const vector<Constraint>& constraints,
1388 
1389  // Evaluate constraints at the point described by X and Y (well-measured
1390  // and poorly-measured variables, respectively). The results should
1391  // be stored in F. BX and BY should be set to the gradients of F with
1392  // respect to X and Y, respectively.
1393  //
1394  // Return true if the point X, Y is accepted.
1395  // Return false if it is rejected (i.e., in an unphysical region).
1396  // The constraints need not be evaluated in that case.
1397  virtual bool eval (const Column_Vector& x,
1398  const Column_Vector& y,
1399  Row_Vector& F,
1400  Matrix& Bx,
1401  Matrix& By);
1402 
1403 
1404  // Calculate the constraint functions and gradients.
1406  Matrix& Bx,
1407  Matrix& By) const;
1408 
1409 private:
1410  // The event we're fitting.
1412 
1413  // Vector of constraints.
1414  const vector<Constraint>& _constraints;
1415 
1416  // Argument values.
1418 
1419  // The pair table.
1421 };
1422 
1423 
1435  const vector<Constraint>& constraints,
1437 //
1438 // Purpose: Constructor.
1439 //
1440 // Inputs:
1441 // ev - The event we're fitting.
1442 // constraints - The list of constraints.
1443 // args - The parameter settings.
1444 //
1445 //
1446  : Constraint_Calculator (constraints.size() +
1447  ((ev.has_neutrino() || args.ignore_met()) ? 0 : 2)),
1448  _ev (ev),
1449  _constraints (constraints),
1450  _args (args),
1451  _pt (constraints, ev)
1452 
1453 {
1454 }
1455 
1456 
1471 bool
1473  Matrix& Bx,
1474  Matrix& By) const
1475 //
1476 // Purpose: Calculate the constraint functions and gradients.
1477 //
1478 // Outputs:
1479 // F - Vector of constraint values.
1480 // Bx - The well-measured variable gradients.
1481 // By - The poorly-measured variable gradients.
1482 //
1483 {
1484  // Clear the matrices.
1485  Bx = Matrix (Bx.num_row(), Bx.num_col(), 0);
1486  By = Matrix (By.num_row(), By.num_col(), 0);
1487  F = Row_Vector (F.num_col(), 0);
1488 
1489  const double p_eps = 1e-10;
1490 
1491  if (_ev.has_neutrino() && _ev.nu().z() > _args.e_com()) {
1492  return false;
1493  }
1494 
1495  int nobjs = _ev.nobjs ();
1496 
1497  // Reject the point if any of the momenta get too small.
1498  for (int j=0; j<nobjs; j++) {
1499  if (_ev.obj(j).p.perp() <= p_eps || _ev.obj(j).p.e() <= p_eps) {
1500  return false;
1501  }
1502  }
1503 
1504  if (! calculate_mass_constraints (_ev, _pt, _constraints, _args.use_e(),
1505  F, Bx, By))
1506  return false;
1507 
1508  if (_ev.has_neutrino())
1509  convert_neutrino (_ev, _args.use_e(), Bx, By);
1510  else if (!_args.ignore_met())
1511  {
1512  /* kt constraints */
1513  calculate_kt_constraints (_ev, _args.use_e(), F, Bx);
1514  }
1515 
1516  /* convert d/dtheta to d/deta */
1517  for (int j=0; j<nobjs; j++) {
1518  ddtheta_to_ddeta (obj_index (j) + eta_offs,
1519  _ev.obj(j).p.cosTheta(),
1520  Bx);
1521  }
1522 
1523  /* handle muons */
1524  for (int j=0; j<nobjs; j++) {
1525  const FE_Obj& obj = _ev.obj (j);
1526  if (obj.muon_p) {
1527  // Again, E vs. P doesn't matter here since we assume muons to be massless.
1528  double pmu2 = obj.p.vect().mag2();
1529  int ndx = obj_index (j) + p_offs;
1530  for (int k=1; k<=Bx.num_col(); k++)
1531  Bx(ndx, k) = - Bx(ndx, k) * pmu2;
1532  }
1533  }
1534 
1535  return true;
1536 }
1537 
1538 
1569  const Column_Vector& y,
1570  Row_Vector& F,
1571  Matrix& Bx,
1572  Matrix& By)
1573 //
1574 // Purpose: Evaluate constraints at the point described by X and Y
1575 // (well-measured and poorly-measured variables, respectively).
1576 // The results should be stored in F. BX and BY should be set
1577 // to the gradients of F with respect to X and Y, respectively.
1578 //
1579 // Inputs:
1580 // x - Vector of well-measured variables.
1581 // y - Vector of poorly-measured variables.
1582 //
1583 // Outputs:
1584 // F - Vector of constraint values.
1585 // Bx - The well-measured variable gradients.
1586 // By - The poorly-measured variable gradients.
1587 //
1588 {
1589  int nobjs = _ev.nobjs();
1590 
1591  const double p_eps = 1e-10;
1592  const double eta_max = 10;
1593 
1594  // Give up if we've gone into an obviously unphysical region.
1595  for (int j=0; j<nobjs; j++)
1596  if (x(obj_index (j) + p_offs) < p_eps ||
1597  fabs(x(obj_index (j) + eta_offs)) > eta_max) {
1598  return false;
1599  }
1600 
1601  unpack_event (_ev, x, y, _args.use_e(),
1602  _ev.has_neutrino() || !_args.ignore_met());
1603 
1604  return calculate_constraints (F, Bx, By);
1605 }
1606 
1607 
1608 //*************************************************************************
1609 // Mass calculation.
1610 //
1611 
1612 
1613 namespace {
1614 
1615 
1633 double calculate_sigm (const Matrix& Q,
1634  const Matrix& R,
1635  const Matrix& S,
1636  const Column_Vector& Bx,
1637  const Column_Vector& By)
1638 //
1639 // Purpose: Do error propagation to find the uncertainty in the final mass.
1640 //
1641 // Inputs:
1642 // Q - The final error matrix for the well-measured variables.
1643 // R - The final error matrix for the poorly-measured variables.
1644 // S - The final cross error matrix for the two sets of variables.
1645 // Bx - The well-measured variable gradients.
1646 // By - The poorly-measured variable gradients.
1647 //
1648 {
1649  double sig2 = scalar (Bx.T() * Q * Bx);
1650 
1651  if (By.num_row() > 0) {
1652  sig2 += scalar (By.T() * R * By);
1653  sig2 += 2 * scalar (Bx.T() * S * By);
1654  }
1655 
1656  assert (sig2 >= 0);
1657  return sqrt (sig2);
1658 }
1659 
1660 
1683 void calculate_mass (Fourvec_Event& ev,
1684  const vector<Constraint>& mass_constraint,
1685  const Fourvec_Constrainer_Args& args,
1686  double chisq,
1687  const Matrix& Q,
1688  const Matrix& R,
1689  const Matrix& S,
1690  double& m,
1691  double& sigm)
1692 //
1693 // Purpose: Calculate the final requested mass and its uncertainty.
1694 //
1695 // Inputs:
1696 // ev - The event we're fitting.
1697 // mass_constraint- The description of the mass we're to calculate.
1698 // args - Parameter settings.
1699 // chisq - The chisq from the fit.
1700 // Q - The final error matrix for the well-measured variables.
1701 // R - The final error matrix for the poorly-measured variables.
1702 // S - The final cross error matrix for the two sets of variables.
1703 //
1704 // Outputs:
1705 // m - The mass.
1706 // sigm - Its uncertainty.
1707 //
1708 {
1709  // Don't do anything if the mass wasn't specified.
1710  if (mass_constraint.size () == 0) {
1711  m = 0;
1712  sigm = 0;
1713  return;
1714  }
1715 
1716  // Do the constraint calculation.
1717  int n_measured_vars = ev.nobjs()*3 + 2;
1718  int n_unmeasured_vars = 0;
1719  if (ev.has_neutrino ()) n_unmeasured_vars = 1;
1720 
1721  Row_Vector F(1);
1722  Matrix Bx (n_measured_vars, 1);
1723  Matrix By (n_unmeasured_vars, 1);
1724 
1725  Fourvec_Constraint_Calculator cc (ev, mass_constraint, args);
1726  cc.calculate_constraints (F, Bx, By);
1727 
1728  // Calculate the mass.
1729  //assert (F(1) >= 0);
1730  if (F(1) >= 0.)
1731  m = sqrt (F(1) * 2);
1732  else {
1733  m = 0.;
1734  chisq = -100.;
1735  }
1736 
1737  // And the uncertainty.
1738  // We can only do this if the fit converged.
1739  if (chisq < 0)
1740  sigm = 0;
1741  else {
1742  //assert (F(1) > 0);
1743  Bx = Bx / (m);
1744  By = By / (m);
1745 
1746  sigm = calculate_sigm (Q, R, S, Bx, By);
1747  }
1748 }
1749 
1750 
1751 } // unnamed namespace
1752 
1753 
1755  double& m,
1756  double& sigm,
1757  Column_Vector& pullx,
1758  Column_Vector& pully)
1759 //
1760 // Purpose: Do a constrained fit for EV. Returns the requested mass and
1761 // its error in M and SIGM, and the pull quantities in PULLX and
1762 // PULLY. Returns the chisq; this will be < 0 if the fit failed
1763 // to converge.
1764 //
1765 // Inputs:
1766 // ev - The event we're fitting.
1767 //
1768 // Outputs:
1769 // ev - The fitted event.
1770 // m - Requested invariant mass.
1771 // sigm - Uncertainty on m.
1772 // pullx - Pull quantities for well-measured variables.
1773 // pully - Pull quantities for poorly-measured variables.
1774 //
1775 // Returns:
1776 // The fit chisq, or < 0 if the fit didn't converge.
1777 //
1778 {
1779  adjust_fourvecs (ev, _args.use_e ());
1780 
1781  bool use_kt = ev.has_neutrino() || !_args.ignore_met();
1782  int nobjs = ev.nobjs ();
1783  int n_measured_vars = nobjs * 3;
1784  int n_unmeasured_vars = 0;
1785  int n_constraints = _constraints.size ();
1786 
1787  if (use_kt) {
1788  n_measured_vars += 2;
1789 
1790  if (ev.has_neutrino ())
1791  n_unmeasured_vars = 1;
1792  else
1793  n_constraints += 2;
1794  }
1795 
1796  Matrix G_i (n_measured_vars, n_measured_vars);
1797  Diagonal_Matrix Y (n_unmeasured_vars);
1798  Column_Vector x (n_measured_vars);
1799  Column_Vector y (n_unmeasured_vars);
1800  pack_event (ev, _args.use_e(), use_kt, x, y, G_i, Y);
1801 
1802  Column_Vector xm = x;
1803  Column_Vector ym = y;
1804 
1805  // ??? Should allow for using a different underlying fitter here.
1807 
1809 
1810  Matrix Q;
1811  Matrix R;
1812  Matrix S;
1813  double chisq = fitter.fit (cc,
1814  xm, x, ym, y, G_i, Y,
1815  pullx, pully,
1816  Q, R, S);
1817 
1818  unpack_event (ev, x, y, _args.use_e (), use_kt);
1819 
1820  calculate_mass (ev, _mass_constraint, _args, chisq, Q, R, S, m, sigm);
1821 
1822  return chisq;
1823 }
1824 
1825 
1826 } // namespace hitfit
tuple base
Main Program
Definition: newFWLiteAna.py:92
int i
Definition: DBlmapReader.cc:9
Define an abstract interface for getting parameter settings.
Represent a mass constraint equation. Mass constraints come in two varieties, either saying that the ...
Definition: Constraint.h:80
void adjust_e_for_mass(Fourvec &v, double mass)
Adjust the energy component of four-vector v (leaving the three-vector part unchanged) so that the fo...
Definition: fourvec.cc:124
Represent an event for kinematic fitting as a collection of four-momenta. Each object is represented ...
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
Fourvec_Constrainer(const Fourvec_Constrainer_Args &args)
Constructor.
CLHEP::HepVector Column_Vector
Definition: matutil.h:67
Concrete realization of the Constraint_Calculator class. Evaluate constraints at the point described ...
Define matrix types for the HitFit package, and supply a few additional operations.
T eta() const
uint16_t size_type
int nobjs() const
Return the number of objects in the event not including any neutrinos.
Abstract base class for evaluating constraints. Users derive from this class and implement the eval()...
CLHEP::HepMatrix Matrix
Definition: matutil.h:66
Fourvec_Constrainer_Args(const Defaults &defs)
Constructor, initialize from a Defaults object.
bool calculate_constraints(Row_Vector &F, Matrix &Bx, Matrix &By) const
Calculate the constraint functions and gradients.
T sqrt(T t)
Definition: SSEVec.h:48
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
Minimize a subject to a set of constraints. Based on the SQUAW algorithm.
Minimize a subject to a set of constraints, based on the SQUAW algorithm.
CLHEP::HepLorentzVector Fourvec
Typedef for a HepLorentzVector.
Definition: fourvec.h:58
int j
Definition: DBlmapReader.cc:9
const Chisq_Constrainer_Args & chisq_constrainer_args() const
Hold on to parameters for the Chisq_Constrainer class.
const Fourvec_Constrainer_Args _args
double p2[4]
Definition: TauolaWrapper.h:90
void adjust_p_for_mass(Fourvec &v, double mass)
Adjust the three-vector part of v, leaving the energy unchanged,.
Definition: fourvec.cc:99
std::vector< Constraint > _mass_constraint
Fourvec_Constraint_Calculator(Fourvec_Event &ev, const vector< Constraint > &constraints, const Fourvec_Constrainer_Args &args)
Constructor.
int k[5][pyjets_maxn]
Float e1
Definition: deltaR.h:22
CLHEP::HepDiagMatrix Diagonal_Matrix
Definition: matutil.h:68
A lookup table to speed up constraint evaluation using Fourvec_Constrainer.
Definition: Pair_Table.h:100
string const
Definition: compareJSON.py:14
Float e2
Definition: deltaR.h:23
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
Chisq_Constrainer_Args _chisq_constrainer_args
dictionary args
std::vector< Constraint > _constraints
double p1[4]
Definition: TauolaWrapper.h:89
T dot(const Basic3DVector &v) const
Scalar product, or &quot;dot&quot; product, with a vector of same type.
double constrain(Fourvec_Event &ev, double &m, double &sigm, Column_Vector &pullx, Column_Vector &pully)
Do a constrained fit for event ev. Returns the requested mass and its uncertainty in m and sigm...
if(dp >Float(M_PI)) dp-
Define an interface for getting parameter settings.
Definition: Defaults.h:62
std::ostream & operator<<(std::ostream &s, const Constraint_Intermed &ci)
Output stream operator, print the content of this Constraint_Intermed to an output stream...
virtual bool eval(const Column_Vector &x, const Column_Vector &y, Row_Vector &F, Matrix &Bx, Matrix &By)
Evaluate constraints at the point described by x and y (well-measured and poorly-measured variables...
const Fourvec_Constrainer_Args & _args
Do a kinematic fit for a set of four-vectors, given a set of mass constraints.
void mass_constraint(std::string s)
Specify a combination of objects that will be returned by the constrain() method as mass...
Definition: DDAxes.h:10
Represent a single object in a Fourvec_Event, this is just a dumb data container. Each object in a Fo...
Definition: Fourvec_Event.h:95
static uInt32 F(BLOWFISH_CTX *ctx, uInt32 x)
Definition: blowfish.cc:281
const vector< Constraint > & _constraints
void add_constraint(std::string s)
Specify an additional constraint s for the problem. The format for s is described in the class descri...
Do a kinematic fit for a set of four-momenta, given a set of mass constraints.
A lookup table to speed up constraint evaluation.
Row-vector class. CLHEP doesn&#39;t have a row-vector class, so HitFit uses its own. This is only a simpl...
Definition: matutil.h:84
Hold on to parameters for the Fourvec_Constrainer class.
double scalar(const CLHEP::HepGenMatrix &m)
Return the matrix as a scalar. Raise an assertion if the matris is not .
Definition: matutil.cc:184
Represent an event for kinematic fitting as a collection of four-momenta.
Definition: DDAxes.h:10
bool has_neutrino() const
Return TRUE is this event contains a neutrino, otherwise returns FALSE.