CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Fourvec_Constrainer.cc
Go to the documentation of this file.
1 //
2 //
3 // File: src/Fourvec_Constrainer.cc
4 // Purpose: Do a kinematic fit for a set of 4-vectors, given a set
5 // of mass constraints.
6 // Created: Jul, 2000, sss, based on run 1 mass analysis code.
7 //
8 // CMSSW File : src/Fourvec_Constrainer.cc
9 // Original Author : Scott Stuart Snyder <snyder@bnl.gov> for D0
10 // Imported to CMSSW by Haryo Sumowidagdo <Suharyo.Sumowidagdo@cern.ch>
11 //
12 
45 #include <cmath>
46 #include <iostream>
47 
48 using std::cos;
49 using std::exp;
50 using std::ostream;
51 using std::sin;
52 using std::sqrt;
53 using std::vector;
54 
55 namespace hitfit {
56 
57  //*************************************************************************
58  // Argument handling.
59  //
60 
62  //
63  // Purpose: Constructor.
64  //
65  // Inputs:
66  // defs - The Defaults instance from which to initialize.
67  //
68  : _use_e(defs.get_bool("use_e")),
69  _e_com(defs.get_float("e_com")),
70  _ignore_met(defs.get_bool("ignore_met")),
71  _chisq_constrainer_args(defs) {}
72 
74  //
75  // Purpose: Return the use_e parameter.
76  // See the header for documentation.
77  //
78  {
79  return _use_e;
80  }
81 
83  //
84  // Purpose: Return the e_com parameter.
85  // See the header for documentation.
86  //
87  {
88  return _e_com;
89  }
90 
92  //
93  // Purpose: Return the ignore_met parameter.
94  // See the header for documentation.
95  //
96  {
97  return _ignore_met;
98  }
99 
101  //
102  // Purpose: Return the contained subobject parameters.
103  //
104  {
106  }
107 
108  //*************************************************************************
109  // Variable layout.
110  //
111  // We need to map the quantities we fit onto the vectors of well- and
112  // poorly-measured quantities.
113  //
114 
115  //
116  // The well-measured variables consist of three variables for each
117  // object. If we are using transverse momentum constraints,
118  // these fill be followed by the two cartesian components of kt.
119  //
120  // Each object is represented by three variables: the momentum (or 1/p
121  // if the muon flag was set), and the two spherical angles, phi and eta.
122  // Here is how they're ordered.
123  //
127  typedef enum { p_offs = 0, phi_offs = 1, eta_offs = 2 } Offsets;
128 
133  typedef enum { x_offs = 0, y_offs = 1 } Kt_Offsets;
134 
135  //
136  // If there is a neutrino, then it is at index 1 of the poorly-measured
137  // set (otherwise, that set is empty).
138  //
143  typedef enum { nu_z = 1 } Unmeasured_Variables;
144 
145  namespace {
146 
153  int obj_index(int i)
154  //
155  // Purpose: Return the starting variable index for object I.
156  //
157  // Inputs:
158  // i - The object index.
159  //
160  // Returns:
161  // The index in the well-measured set of the first variable
162  // for object I.
163  //
164  {
165  return i * 3 + 1;
166  }
167 
168  } // unnamed namespace
169 
170  //*************************************************************************
171  // Object management.
172  //
173 
175  //
176  // Purpose: Constructor.
177  //
178  // Inputs:
179  // args - The parameter settings for this instance.
180  //
181  : _args(args) {}
182 
184  //
185  // Purpose: Specify an additional constraint S for the problem.
186  // The format for S is described in the header.
187  //
188  // Inputs:
189  // s - The constraint to add.
190  //
191  {
192  _constraints.push_back(Constraint(s));
193  }
194 
196  //
197  // Purpose: Specify the combination of objects that will be returned by
198  // constrain() as the mass. The format of S is the same as for
199  // normal constraints. The LHS specifies the mass to calculate;
200  // the RHS should be zero.
201  // This should only be called once.
202  //
203  // Inputs:
204  // s - The constraint defining the mass.
205  //
206  {
207  assert(_mass_constraint.empty());
208  _mass_constraint.push_back(Constraint(s));
209  }
210 
220  std::ostream& operator<<(std::ostream& s, const Fourvec_Constrainer& c)
221  //
222  // Purpose: Print the object to S.
223  //
224  // Inputs:
225  // s - The stream to which to write.
226  // c - The object to write.
227  //
228  // Returns:
229  // The stream S.
230  //
231  {
232  s << "Constraints: (e_com = " << c._args.e_com() << ") ";
233  if (c._args.use_e())
234  s << "(E)";
235  s << "\n";
236 
237  for (std::vector<Constraint>::size_type i = 0; i < c._constraints.size(); i++)
238  s << " " << c._constraints[i] << "\n";
239 
240  if (!c._mass_constraint.empty()) {
241  s << "Mass constraint:\n";
242  s << c._mass_constraint[0] << "\n";
243  }
244  return s;
245  }
246 
247  //*************************************************************************
248  // Event packing and unpacking.
249  //
250 
251  namespace {
252 
263  void adjust_fourvecs(Fourvec_Event& ev, bool use_e_flag)
264  //
265  // Purpose: For all objects in EV, adjust their 4-momenta
266  // to have their requested masses.
267  //
268  // Inputs:
269  // ev - The event on which to operate.
270  // use_e_flag - If true, keep E and scale 3-momentum.
271  // If false, keep the 3-momentum and scale E.
272  //
273  {
274  int nobjs = ev.nobjs();
275  for (int i = 0; i < nobjs; i++) {
276  const FE_Obj& obj = ev.obj(i);
277  Fourvec p = obj.p;
278  if (use_e_flag)
279  adjust_p_for_mass(p, obj.mass);
280  else
281  adjust_e_for_mass(p, obj.mass);
282  ev.set_obj_p(i, p);
283  }
284  }
285 
302  Fourvec get_p_eta_phi_vec(const Column_Vector& c, int ndx, const FE_Obj& obj, bool use_e_flag)
303  //
304  // Purpose: Convert object NDX from its representation in the set
305  // of well-measured variables C to a 4-vector.
306  //
307  // Inputs:
308  // c - The vector of well-measured variables.
309  // ndx - The index of the object in which we're interested.
310  // obj - The object from the Fourvec_Event.
311  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
312  //
313  // Returns:
314  // The object's 4-momentum.
315  //
316  {
317  // Get the energy and momentum of the object.
318  double e, p;
319 
320  if (use_e_flag) {
321  // We're using E as a fit variable. Get it directly.
322  e = c(ndx + p_offs);
323 
324  // Take into account the muon case.
325  if (obj.muon_p)
326  e = 1 / e;
327 
328  // Find the momentum given the energy.
329  if (obj.mass == 0)
330  p = e;
331  else {
332  double xx = e * e - obj.mass * obj.mass;
333  if (xx >= 0)
334  p = sqrt(xx);
335  else
336  p = 0;
337  }
338  } else {
339  // We're using P as a fit variable. Fetch it.
340  p = c(ndx + p_offs);
341 
342  // Take into account the muon case.
343  if (obj.muon_p)
344  p = 1 / p;
345 
346  // Find the energy given the momentum.
347  e = (obj.mass == 0 ? p : sqrt(obj.mass * obj.mass + p * p));
348  }
349 
350  // Get angular variables.
351  double phi = c(ndx + phi_offs);
352  double eta = c(ndx + eta_offs);
353  if (fabs(eta) > 50) {
354  // Protect against ridiculously large etas
355  eta = eta > 0 ? 50 : -50;
356  }
357  double exp_eta = exp(eta);
358  double iexp_eta = 1 / exp_eta;
359  double sin_theta = 2 / (exp_eta + iexp_eta);
360  double cos_theta = (exp_eta - iexp_eta) / (exp_eta + iexp_eta);
361 
362  // Form the 4-momentum.
363  return Fourvec(p * sin_theta * cos(phi), p * sin_theta * sin(phi), p * cos_theta, e);
364  }
365 
382  void set_p_eta_phi_vec(const FE_Obj& obj, Column_Vector& c, int ndx, bool use_e_flag)
383  //
384  // Purpose: Initialize the variables in the well-measured set C describing
385  // object NDX from its Fourvec_Event representation OBJ.
386  //
387  // Inputs:
388  // obj - The object from the Fourvec_Event.
389  // c - The vector of well-measured variables.
390  // ndx - The index of the object in which we're interested.
391  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
392  //
393  //
394  {
395  if (use_e_flag)
396  c(ndx + p_offs) = obj.p.e();
397  else
398  c(ndx + p_offs) = obj.p.vect().mag();
399 
400  if (obj.muon_p)
401  c(ndx + p_offs) = 1 / c(ndx + p_offs);
402  c(ndx + phi_offs) = obj.p.phi();
403  c(ndx + eta_offs) = obj.p.pseudoRapidity();
404  }
405 
415  Matrix error_matrix(double p_sig, double phi_sig, double eta_sig)
416  //
417  // Purpose: Set up the 3x3 error matrix for an object.
418  //
419  // Inputs:
420  // p_sig - The momentum uncertainty.
421  // phi_sig - The phi uncertainty.
422  // eta_sig - The eta uncertainty.
423  //
424  // Returns:
425  // The object's error matrix.
426  //
427  {
428  Matrix err(3, 3, 0);
429  err(1 + p_offs, 1 + p_offs) = p_sig * p_sig;
430  err(1 + phi_offs, 1 + phi_offs) = phi_sig * phi_sig;
431  err(1 + eta_offs, 1 + eta_offs) = eta_sig * eta_sig;
432  return err;
433  }
434 
460  void pack_event(const Fourvec_Event& ev,
461  bool use_e_flag,
462  bool use_kt_flag,
463  Column_Vector& xm,
464  Column_Vector& ym,
465  Matrix& G_i,
467  //
468  // Purpose: Take the information from a Fourvec_Event EV and pack
469  // it into vectors of well- and poorly-measured variables.
470  // Also set up the error matrices.
471  //
472  // Inputs:
473  // ev - The event to pack.
474  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
475  // use_kt_flag - True if we're to pack kt variables.
476  //
477  // Outputs:
478  // xm - Vector of well-measured variables.
479  // ym - Vector of poorly-measured variables.
480  // G_i - Error matrix for well-measured variables.
481  // Y - Inverse error matrix for poorly-measured variables.
482  //
483  {
484  // Number of objects in the event.
485  int nobjs = ev.nobjs();
486 
487  int n_measured_vars = nobjs * 3;
488  if (use_kt_flag)
489  n_measured_vars += 2;
490 
491  // Clear the error matrix.
492  G_i = Matrix(n_measured_vars, n_measured_vars, 0);
493 
494  // Loop over objects.
495  for (int i = 0; i < nobjs; i++) {
496  const FE_Obj& obj = ev.obj(i);
497  int this_index = obj_index(i);
498  set_p_eta_phi_vec(obj, xm, this_index, use_e_flag);
499  G_i.sub(this_index, this_index, error_matrix(obj.p_error, obj.phi_error, obj.eta_error));
500  }
501 
502  if (use_kt_flag) {
503  // Set up kt.
504  int kt_ndx = obj_index(nobjs);
505  xm(kt_ndx + x_offs) = ev.kt().x();
506  xm(kt_ndx + y_offs) = ev.kt().y();
507 
508  // And its error matrix.
509  G_i(kt_ndx + x_offs, kt_ndx + x_offs) = ev.kt_x_error() * ev.kt_x_error();
510  G_i(kt_ndx + y_offs, kt_ndx + y_offs) = ev.kt_y_error() * ev.kt_y_error();
511  G_i(kt_ndx + x_offs, kt_ndx + y_offs) = ev.kt_xy_covar();
512  G_i(kt_ndx + y_offs, kt_ndx + x_offs) = ev.kt_xy_covar();
513  }
514 
515  // Handle a neutrino.
516  if (ev.has_neutrino()) {
517  ym(nu_z) = ev.nu().z();
518  Y = Diagonal_Matrix(1, 0);
519  }
520  }
521 
541  void unpack_event(
542  Fourvec_Event& ev, const Column_Vector& x, const Column_Vector& y, bool use_e_flag, bool use_kt_flag)
543  //
544  // Purpose: Update the contents of EV from the variable sets X and Y.
545  //
546  // Inputs:
547  // ev - The event.
548  // x - Vector of well-measured variables.
549  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
550  // use_kt_flag - True if we're too unpack kt variables.
551  //
552  // Outputs:
553  // ev - The event after updating.
554  //
555  {
556  // Do all the objects.
557  Fourvec sum = Fourvec(0);
558  for (int j = 0; j < ev.nobjs(); j++) {
559  const FE_Obj& obj = ev.obj(j);
560  ev.set_obj_p(j, get_p_eta_phi_vec(x, obj_index(j), obj, use_e_flag));
561  sum += obj.p;
562  }
563 
564  if (use_kt_flag) {
565  int kt_ndx = obj_index(ev.nobjs());
566  Fourvec kt = Fourvec(x(kt_ndx + x_offs), x(kt_ndx + y_offs), 0, 0);
567  Fourvec nu = kt - sum;
568  if (ev.has_neutrino()) {
569  nu.setPz(y(nu_z));
570  adjust_e_for_mass(nu, 0);
571  ev.set_nu_p(nu);
572  } else {
573  adjust_e_for_mass(nu, 0);
574  ev.set_x_p(nu);
575  }
576  }
577  }
578 
579  } // unnamed namespace
580 
581  //*************************************************************************
582  // Constraint evaluation.
583  //
584 
585  namespace {
586 
615  double dot_and_gradient(
616  const Fourvec& v1, const Fourvec& v2, bool use_e_flag, double v1_x[3], double v2_x[3], bool& badflag)
617  //
618  // Purpose: Compute the dot product v1.v2 and its gradients wrt
619  // p, phi, and theta of each 4-vector.
620  //
621  // Inputs:
622  // v1 - The first 4-vector in the dot product.
623  // v2 - The second 4-vector in the dot product.
624  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
625  //
626  // Outputs:
627  // v1_x - Gradients of the dot product wrt v1's p, phi, theta.
628  // v2_x - Gradients of the dot product wrt v2's p, phi, theta.
629  // badflag - Set to true for the singular case (vectors vanish).
630  //
631  // Returns:
632  // The dot product.
633  //
634  {
635  // Calculate the dot product.
636  double dot = v1 * v2;
637 
638  double p1 = v1.vect().mag();
639  double p2 = v2.vect().mag();
640  double e1 = v1.e();
641  double e2 = v2.e();
642  double pt1 = v1.vect().perp();
643  double pt2 = v2.vect().perp();
644 
645  // Protect against the singular case.
646  badflag = false;
647  if (p1 == 0 || p2 == 0 || e1 == 0 || e2 == 0 || pt1 == 0 || pt2 == 0) {
648  badflag = true;
649  v1_x[p_offs] = v1_x[phi_offs] = v1_x[eta_offs] = 0;
650  v2_x[p_offs] = v2_x[phi_offs] = v2_x[eta_offs] = 0;
651  return false;
652  }
653 
654  // Calculate the gradients.
655  v1_x[p_offs] = (dot - v1.m2() * e2 / e1) / p1;
656  v2_x[p_offs] = (dot - v2.m2() * e1 / e2) / p2;
657 
658  if (use_e_flag) {
659  v1_x[p_offs] *= e1 / p1;
660  v2_x[p_offs] *= e2 / p2;
661  }
662 
663  v1_x[phi_offs] = v1(1) * v2(0) - v1(0) * v2(1);
664  v2_x[phi_offs] = -v1_x[phi_offs];
665 
666  double fac = v1(0) * v2(0) + v1(1) * v2(1);
667  v1_x[eta_offs] = pt1 * v2(2) - v1(2) / pt1 * fac;
668  v2_x[eta_offs] = pt2 * v1(2) - v2(2) / pt2 * fac;
669 
670  return dot;
671  }
672 
694  void addin_obj_gradient(int constraint_no, int sign, int base_index, const double grad[], Matrix& Bx)
695  //
696  // Purpose: Tally up the dot product gradients for an object
697  // into Bx.
698  //
699  // Inputs:
700  // constraint_no-The number of the constraint.
701  // base_index - The index in the well-measured variable list
702  // of the first variable for this object.
703  // sign - The sign with which these gradients should be
704  // added into Bx, either +1 or -1. (I.e., which
705  // side of the constraint equation.)
706  // grad - The gradients for this object, vs. p, phi, theta.
707  // Bx - The well-measured variable gradients.
708  //
709  // Outputs:
710  // Bx - The well-measured variable gradients, updated.
711  //
712  {
713  Bx(base_index + p_offs, constraint_no) += sign * grad[p_offs];
714  Bx(base_index + phi_offs, constraint_no) += sign * grad[phi_offs];
715  Bx(base_index + eta_offs, constraint_no) += sign * grad[eta_offs];
716  }
717 
745  void addin_nu_gradient(int constraint_no, int sign, int kt_ndx, const double grad[], Matrix& Bx, Matrix& By)
746  //
747  // Purpose: Tally up the dot product gradients for a neutrino
748  // into Bx and By.
749  //
750  // Inputs:
751  // constraint_no-The number of the constraint.
752  // sign - The sign with which these gradients should be
753  // added into Bx, either +1 or -1. (I.e., which
754  // side of the constraint equation.)
755  // kt_ndx - The index of the kt variables in the variables array.
756  // grad - The gradients for this object, vs. p, phi, theta.
757  // Bx - The well-measured variable gradients.
758  // By - The poorly-measured variable gradients.
759  //
760  // Outputs:
761  // Bx - The well-measured variable gradients, updated.
762  // By - The poorly-measured variable gradients, updated.
763  //
764  {
765  Bx(kt_ndx + x_offs, constraint_no) += sign * grad[p_offs]; // Really p for now.
766  Bx(kt_ndx + y_offs, constraint_no) += sign * grad[phi_offs]; // Really phi for now.
767  By(nu_z, constraint_no) += sign * grad[eta_offs]; // Really theta ...
768  }
769 
796  void addin_gradient(
797  const Fourvec_Event& ev, int constraint_no, int sign, int obj_no, const double grad[], Matrix& Bx, Matrix& By)
798  //
799  // Purpose: Tally up the dot product gradients for an object (which may
800  // or may not be a neutrino) into Bx and By.
801  //
802  // Inputs:
803  // ev - The event we're fitting.
804  // constraint_no-The number of the constraint.
805  // sign - The sign with which these gradients should be
806  // added into Bx, either +1 or -1. (I.e., which
807  // side of the constraint equation.)
808  // obj_no - The number of the object.
809  // grad - The gradients for this object, vs. p, phi, theta.
810  // Bx - The well-measured variable gradients.
811  // By - The poorly-measured variable gradients.
812  //
813  // Outputs:
814  // Bx - The well-measured variable gradients, updated.
815  // By - The poorly-measured variable gradients, updated.
816  //
817  {
818  if (obj_no >= ev.nobjs()) {
819  assert(obj_no == ev.nobjs());
820  addin_nu_gradient(constraint_no, sign, obj_index(obj_no), grad, Bx, By);
821  } else
822  addin_obj_gradient(constraint_no, sign, obj_index(obj_no), grad, Bx);
823  }
824 
855  void addin_gradients(const Fourvec_Event& ev,
856  int constraint_no,
857  int sign,
858  int i,
859  const double igrad[],
860  int j,
861  const double jgrad[],
862  Matrix& Bx,
863  Matrix& By)
864  //
865  // Purpose: Tally up the gradients from a single dot product into Bx and By.
866  //
867  // Inputs:
868  // ev - The event we're fitting.
869  // constraint_no-The number of the constraint.
870  // sign - The sign with which these gradients should be
871  // added into Bx, either +1 or -1. (I.e., which
872  // side of the constraint equation.)
873  // i - The number of the first object.
874  // igrad - The gradients for the first object, vs. p, phi, theta.
875  // j - The number of the second object.
876  // jgrad - The gradients for the second object, vs. p, phi, theta.
877  // Bx - The well-measured variable gradients.
878  // By - The poorly-measured variable gradients.
879  //
880  // Outputs:
881  // Bx - The well-measured variable gradients, updated.
882  // By - The poorly-measured variable gradients, updated.
883  //
884  {
885  addin_gradient(ev, constraint_no, sign, i, igrad, Bx, By);
886  addin_gradient(ev, constraint_no, sign, j, jgrad, Bx, By);
887  }
888 
901  void add_mass_terms(const Fourvec_Event& ev, const vector<Constraint>& constraints, Row_Vector& F)
902  //
903  // Purpose: Add the m^2 terms into the constraint values.
904  //
905  // Inputs:
906  // ev - The event we're fitting.
907  // constraints - The list of constraints.
908  // F - Vector of constraint values.
909  //
910  // Outputs:
911  // F - Vector of constraint values, updated.
912  //
913  {
914  for (std::vector<Constraint>::size_type i = 0; i < constraints.size(); i++)
915  F(i + 1) += constraints[i].sum_mass_terms(ev);
916  }
917 
951  bool calculate_mass_constraints(const Fourvec_Event& ev,
952  const Pair_Table& pt,
953  const vector<Constraint>& constraints,
954  bool use_e_flag,
955  Row_Vector& F,
956  Matrix& Bx,
957  Matrix& By)
958  //
959  // Purpose: Calculate the mass constraints and gradients.
960  // Note: At this stage, the gradients are calculated not
961  // quite with respect to the fit variables; instead, for
962  // all objects (including the neutrino) we calculate
963  // the gradients with respect to p, phi, theta. They'll
964  // be converted via appropriate Jacobian transformations
965  // later.
966  //
967  // Inputs:
968  // ev - The event we're fitting.
969  // pt - Table of cached pair assignments.
970  // constraints - The list of constraints.
971  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
972  //
973  // Outputs:
974  // (nb. these should be passed in correctly dimensioned.)
975  // F - Vector of constraint values.
976  // Bx - The well-measured variable gradients.
977  // By - The poorly-measured variable gradients.
978  //
979  {
980  int npairs = pt.npairs();
981  for (int p = 0; p < npairs; p++) {
982  const Objpair& objpair = pt.get_pair(p);
983  int i = objpair.i();
984  int j = objpair.j();
985  double igrad[3], jgrad[3];
986  bool badflag = false;
987  double dot = dot_and_gradient(ev.obj(i).p, ev.obj(j).p, use_e_flag, igrad, jgrad, badflag);
988  if (badflag)
989  return false;
990 
991  for (std::vector<Constraint>::size_type k = 0; k < constraints.size(); k++)
992  if (objpair.for_constraint(k)) {
993  F(k + 1) += objpair.for_constraint(k) * dot;
994  addin_gradients(ev, k + 1, objpair.for_constraint(k), i, igrad, j, jgrad, Bx, By);
995  }
996  }
997 
998  add_mass_terms(ev, constraints, F);
999  return true;
1000  }
1001 
1024  void add_nuterm(unsigned ndx, const Fourvec& v, Matrix& Bx, bool use_e_flag, int kt_ndx)
1025  //
1026  // Purpose: Carry out the Jacobian transformation for
1027  // (p_nu^x,p_nu_y) -> (kt^x, kt_y) for a given object.
1028  //
1029  // Inputs:
1030  // ndx - Index of the object for which to transform gradients.
1031  // v - The object's 4-momentum.
1032  // Bx - The well-measured variable gradients.
1033  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1034  // kt_ndx - The index of the kt variables in the variables array.
1035  //
1036  // Outputs:
1037  // Bx - The well-measured variable gradients, updated.
1038  //
1039  {
1040  double px = v.px();
1041  double py = v.py();
1042  double cot_theta = v.pz() / v.vect().perp();
1043 
1044  for (int j = 1; j <= Bx.num_col(); j++) {
1045  double dxnu = Bx(kt_ndx + x_offs, j);
1046  double dynu = Bx(kt_ndx + y_offs, j);
1047 
1048  if (dxnu != 0 || dynu != 0) {
1049  double fac = 1 / v.vect().mag();
1050  if (use_e_flag)
1051  fac = v.e() * fac * fac;
1052  Bx(ndx + p_offs, j) -= (px * dxnu + py * dynu) * fac;
1053  Bx(ndx + phi_offs, j) += py * dxnu - px * dynu;
1054  Bx(ndx + eta_offs, j) -= (px * dxnu + py * dynu) * cot_theta;
1055  }
1056  }
1057  }
1058 
1082  void convert_neutrino(const Fourvec_Event& ev, bool use_e_flag, Matrix& Bx, Matrix& By)
1083  //
1084  // Purpose: Carry out the Jacobian transformations the neutrino.
1085  // First, convert from spherical (p, phi, theta) coordinates
1086  // to rectangular (x, y, z). Then convert from neutrino pt
1087  // components to kt components.
1088  //
1089  // Inputs:
1090  // ev - The event we're fitting.
1091  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1092  // Bx - The well-measured variable gradients.
1093  // By - The poorly-measured variable gradients.
1094  //
1095  // Outputs:
1096  // Bx - The well-measured variable gradients, updated.
1097  // By - The poorly-measured variable gradients, updated.
1098  //
1099  {
1100  int nconstraints = Bx.num_col();
1101 
1102  const Fourvec& nu = ev.nu();
1103 
1104  // convert neutrino from polar coordinates to rectangular.
1105  double pnu2 = nu.vect().mag2();
1106  double pnu = sqrt(pnu2);
1107  double ptnu2 = nu.vect().perp2();
1108  double ptnu = sqrt(ptnu2);
1109 
1110  // Doesn't matter whether we use E or P here, since nu is massless.
1111 
1112  double thfac = nu.z() / pnu2 / ptnu;
1113  double fac[3][3];
1114  fac[0][0] = nu(0) / pnu;
1115  fac[0][1] = nu(1) / pnu;
1116  fac[0][2] = nu(2) / pnu;
1117  fac[1][0] = -nu(1) / ptnu2;
1118  fac[1][1] = nu(0) / ptnu2;
1119  fac[1][2] = 0;
1120  fac[2][0] = nu(0) * thfac;
1121  fac[2][1] = nu(1) * thfac;
1122  fac[2][2] = -ptnu / pnu2;
1123 
1124  int kt_ndx = obj_index(ev.nobjs());
1125  for (int j = 1; j <= nconstraints; j++) {
1126  double tmp1 = fac[0][0] * Bx(kt_ndx + x_offs, j) + fac[1][0] * Bx(kt_ndx + y_offs, j) + fac[2][0] * By(nu_z, j);
1127  Bx(kt_ndx + y_offs, j) =
1128  fac[0][1] * Bx(kt_ndx + x_offs, j) + fac[1][1] * Bx(kt_ndx + y_offs, j) + fac[2][1] * By(nu_z, j);
1129  By(nu_z, j) = fac[0][2] * Bx(kt_ndx + x_offs, j) + fac[2][2] * By(nu_z, j);
1130 
1131  Bx(kt_ndx + x_offs, j) = tmp1;
1132  }
1133 
1134  // Add nu terms.
1135  for (int j = 0; j < ev.nobjs(); j++) {
1136  add_nuterm(obj_index(j), ev.obj(j).p, Bx, use_e_flag, kt_ndx);
1137  }
1138  }
1139 
1160  void calculate_kt_constraints(const Fourvec_Event& ev, bool use_e_flag, Row_Vector& F, Matrix& Bx)
1161  //
1162  // Purpose: Calculate the overall kt constraints (kt = 0) for the case
1163  // where there is no neutrino.
1164  //
1165  // Inputs:
1166  // ev - The event we're fitting.
1167  // use_e_flag - If true, we're using E as the fit variable, otherwise p.
1168  // F - Vector of constraint values.
1169  // Bx - The well-measured variable gradients.
1170  //
1171  // Outputs:
1172  // F - Vector of constraint values, updated.
1173  // Bx - The well-measured variable gradients, updated.
1174  //
1175  {
1176  Fourvec tmp = Fourvec(0);
1177  int base = F.num_col() - 2;
1178  int nobjs = ev.nobjs();
1179  for (int j = 0; j < nobjs; j++) {
1180  const Fourvec& obj = ev.obj(j).p;
1181  tmp += obj;
1182 
1183  int ndx = obj_index(j);
1184  double p = obj.vect().mag();
1185  double cot_theta = obj.z() / obj.vect().perp();
1186 
1187  Bx(ndx + p_offs, base + 1) = obj(0) / p;
1188  Bx(ndx + phi_offs, base + 1) = -obj(1);
1189  Bx(ndx + eta_offs, base + 1) = obj(0) * cot_theta;
1190 
1191  Bx(ndx + p_offs, base + 2) = obj(1) / p;
1192  Bx(ndx + phi_offs, base + 2) = obj(0);
1193  Bx(ndx + eta_offs, base + 2) = obj(1) * cot_theta;
1194 
1195  if (use_e_flag) {
1196  Bx(ndx + p_offs, base + 1) *= obj.e() / p;
1197  Bx(ndx + p_offs, base + 2) *= obj.e() / p;
1198  }
1199  }
1200 
1201  int kt_ndx = obj_index(nobjs);
1202  Bx(kt_ndx + x_offs, base + 1) = -1;
1203  Bx(kt_ndx + y_offs, base + 2) = -1;
1204 
1205  F(base + 1) = tmp(0) - ev.kt().x();
1206  F(base + 2) = tmp(1) - ev.kt().y();
1207  }
1208 
1222  void ddtheta_to_ddeta(int i, double cos_theta, Matrix& Bx)
1223  //
1224  // Purpose: Do the Jacobian transformation from theta -> eta
1225  // for a single object.
1226  //
1227  // Inputs:
1228  // i - The index of the object.
1229  // cos_theta - cos(theta) for the object.
1230  // Bx - The well-measured variable gradients.
1231  //
1232  // Outputs:
1233  // Bx - The well-measured variable gradients, updated.
1234  //
1235  {
1236  double sin_theta = sqrt(1 - cos_theta * cos_theta);
1237  for (int j = 1; j <= Bx.num_col(); j++)
1238  Bx(i, j) *= -sin_theta; /* \sin\theta = 1 / \cosh\eta */
1239  }
1240 
1241  } // unnamed namespace
1242 
1269  //
1270  // Purpose: Constraint evaluator.
1271  //
1272  {
1273  public:
1274  // Constructor, destructor.
1276  const vector<Constraint>& constraints,
1279 
1280  // Evaluate constraints at the point described by X and Y (well-measured
1281  // and poorly-measured variables, respectively). The results should
1282  // be stored in F. BX and BY should be set to the gradients of F with
1283  // respect to X and Y, respectively.
1284  //
1285  // Return true if the point X, Y is accepted.
1286  // Return false if it is rejected (i.e., in an unphysical region).
1287  // The constraints need not be evaluated in that case.
1288  bool eval(const Column_Vector& x, const Column_Vector& y, Row_Vector& F, Matrix& Bx, Matrix& By) override;
1289 
1290  // Calculate the constraint functions and gradients.
1291  bool calculate_constraints(Row_Vector& F, Matrix& Bx, Matrix& By) const;
1292 
1293  private:
1294  // The event we're fitting.
1296 
1297  // Vector of constraints.
1298  const vector<Constraint>& _constraints;
1299 
1300  // Argument values.
1302 
1303  // The pair table.
1305  };
1306 
1317  const vector<Constraint>& constraints,
1319  //
1320  // Purpose: Constructor.
1321  //
1322  // Inputs:
1323  // ev - The event we're fitting.
1324  // constraints - The list of constraints.
1325  // args - The parameter settings.
1326  //
1327  //
1328  : Constraint_Calculator(constraints.size() + ((ev.has_neutrino() || args.ignore_met()) ? 0 : 2)),
1329  _ev(ev),
1330  _constraints(constraints),
1331  _args(args),
1332  _pt(constraints, ev)
1333 
1334  {}
1335 
1351  //
1352  // Purpose: Calculate the constraint functions and gradients.
1353  //
1354  // Outputs:
1355  // F - Vector of constraint values.
1356  // Bx - The well-measured variable gradients.
1357  // By - The poorly-measured variable gradients.
1358  //
1359  {
1360  // Clear the matrices.
1361  Bx = Matrix(Bx.num_row(), Bx.num_col(), 0);
1362  By = Matrix(By.num_row(), By.num_col(), 0);
1363  F = Row_Vector(F.num_col(), 0);
1364 
1365  const double p_eps = 1e-10;
1366 
1367  if (_ev.has_neutrino() && _ev.nu().z() > _args.e_com()) {
1368  return false;
1369  }
1370 
1371  int nobjs = _ev.nobjs();
1372 
1373  // Reject the point if any of the momenta get too small.
1374  for (int j = 0; j < nobjs; j++) {
1375  if (_ev.obj(j).p.perp() <= p_eps || _ev.obj(j).p.e() <= p_eps) {
1376  return false;
1377  }
1378  }
1379 
1380  if (!calculate_mass_constraints(_ev, _pt, _constraints, _args.use_e(), F, Bx, By))
1381  return false;
1382 
1383  if (_ev.has_neutrino())
1384  convert_neutrino(_ev, _args.use_e(), Bx, By);
1385  else if (!_args.ignore_met()) {
1386  /* kt constraints */
1387  calculate_kt_constraints(_ev, _args.use_e(), F, Bx);
1388  }
1389 
1390  /* convert d/dtheta to d/deta */
1391  for (int j = 0; j < nobjs; j++) {
1392  ddtheta_to_ddeta(obj_index(j) + eta_offs, _ev.obj(j).p.cosTheta(), Bx);
1393  }
1394 
1395  /* handle muons */
1396  for (int j = 0; j < nobjs; j++) {
1397  const FE_Obj& obj = _ev.obj(j);
1398  if (obj.muon_p) {
1399  // Again, E vs. P doesn't matter here since we assume muons to be massless.
1400  double pmu2 = obj.p.vect().mag2();
1401  int ndx = obj_index(j) + p_offs;
1402  for (int k = 1; k <= Bx.num_col(); k++)
1403  Bx(ndx, k) = -Bx(ndx, k) * pmu2;
1404  }
1405  }
1406 
1407  return true;
1408  }
1409 
1440  const Column_Vector& x, const Column_Vector& y, Row_Vector& F, Matrix& Bx, Matrix& By)
1441  //
1442  // Purpose: Evaluate constraints at the point described by X and Y
1443  // (well-measured and poorly-measured variables, respectively).
1444  // The results should be stored in F. BX and BY should be set
1445  // to the gradients of F with respect to X and Y, respectively.
1446  //
1447  // Inputs:
1448  // x - Vector of well-measured variables.
1449  // y - Vector of poorly-measured variables.
1450  //
1451  // Outputs:
1452  // F - Vector of constraint values.
1453  // Bx - The well-measured variable gradients.
1454  // By - The poorly-measured variable gradients.
1455  //
1456  {
1457  int nobjs = _ev.nobjs();
1458 
1459  const double p_eps = 1e-10;
1460  const double eta_max = 10;
1461 
1462  // Give up if we've gone into an obviously unphysical region.
1463  for (int j = 0; j < nobjs; j++)
1464  if (x(obj_index(j) + p_offs) < p_eps || fabs(x(obj_index(j) + eta_offs)) > eta_max) {
1465  return false;
1466  }
1467 
1468  unpack_event(_ev, x, y, _args.use_e(), _ev.has_neutrino() || !_args.ignore_met());
1469 
1470  return calculate_constraints(F, Bx, By);
1471  }
1472 
1473  //*************************************************************************
1474  // Mass calculation.
1475  //
1476 
1477  namespace {
1478 
1496  double calculate_sigm(
1497  const Matrix& Q, const Matrix& R, const Matrix& S, const Column_Vector& Bx, const Column_Vector& By)
1498  //
1499  // Purpose: Do error propagation to find the uncertainty in the final mass.
1500  //
1501  // Inputs:
1502  // Q - The final error matrix for the well-measured variables.
1503  // R - The final error matrix for the poorly-measured variables.
1504  // S - The final cross error matrix for the two sets of variables.
1505  // Bx - The well-measured variable gradients.
1506  // By - The poorly-measured variable gradients.
1507  //
1508  {
1509  double sig2 = scalar(Bx.T() * Q * Bx);
1510 
1511  if (By.num_row() > 0) {
1512  sig2 += scalar(By.T() * R * By);
1513  sig2 += 2 * scalar(Bx.T() * S * By);
1514  }
1515 
1516  assert(sig2 >= 0);
1517  return sqrt(sig2);
1518  }
1519 
1542  void calculate_mass(Fourvec_Event& ev,
1543  const vector<Constraint>& mass_constraint,
1544  const Fourvec_Constrainer_Args& args,
1545  double chisq,
1546  const Matrix& Q,
1547  const Matrix& R,
1548  const Matrix& S,
1549  double& m,
1550  double& sigm)
1551  //
1552  // Purpose: Calculate the final requested mass and its uncertainty.
1553  //
1554  // Inputs:
1555  // ev - The event we're fitting.
1556  // mass_constraint- The description of the mass we're to calculate.
1557  // args - Parameter settings.
1558  // chisq - The chisq from the fit.
1559  // Q - The final error matrix for the well-measured variables.
1560  // R - The final error matrix for the poorly-measured variables.
1561  // S - The final cross error matrix for the two sets of variables.
1562  //
1563  // Outputs:
1564  // m - The mass.
1565  // sigm - Its uncertainty.
1566  //
1567  {
1568  // Don't do anything if the mass wasn't specified.
1569  if (mass_constraint.empty()) {
1570  m = 0;
1571  sigm = 0;
1572  return;
1573  }
1574 
1575  // Do the constraint calculation.
1576  int n_measured_vars = ev.nobjs() * 3 + 2;
1577  int n_unmeasured_vars = 0;
1578  if (ev.has_neutrino())
1579  n_unmeasured_vars = 1;
1580 
1581  Row_Vector F(1);
1582  Matrix Bx(n_measured_vars, 1);
1583  Matrix By(n_unmeasured_vars, 1);
1584 
1585  Fourvec_Constraint_Calculator cc(ev, mass_constraint, args);
1586  cc.calculate_constraints(F, Bx, By);
1587 
1588  // Calculate the mass.
1589  //assert (F(1) >= 0);
1590  if (F(1) >= 0.)
1591  m = sqrt(F(1) * 2);
1592  else {
1593  m = 0.;
1594  chisq = -100.;
1595  }
1596 
1597  // And the uncertainty.
1598  // We can only do this if the fit converged.
1599  if (chisq < 0)
1600  sigm = 0;
1601  else {
1602  //assert (F(1) > 0);
1603  Bx = Bx / (m);
1604  By = By / (m);
1605 
1606  sigm = calculate_sigm(Q, R, S, Bx, By);
1607  }
1608  }
1609 
1610  } // unnamed namespace
1611 
1613  Fourvec_Event& ev, double& m, double& sigm, Column_Vector& pullx, Column_Vector& pully)
1614  //
1615  // Purpose: Do a constrained fit for EV. Returns the requested mass and
1616  // its error in M and SIGM, and the pull quantities in PULLX and
1617  // PULLY. Returns the chisq; this will be < 0 if the fit failed
1618  // to converge.
1619  //
1620  // Inputs:
1621  // ev - The event we're fitting.
1622  //
1623  // Outputs:
1624  // ev - The fitted event.
1625  // m - Requested invariant mass.
1626  // sigm - Uncertainty on m.
1627  // pullx - Pull quantities for well-measured variables.
1628  // pully - Pull quantities for poorly-measured variables.
1629  //
1630  // Returns:
1631  // The fit chisq, or < 0 if the fit didn't converge.
1632  //
1633  {
1634  adjust_fourvecs(ev, _args.use_e());
1635 
1636  bool use_kt = ev.has_neutrino() || !_args.ignore_met();
1637  int nobjs = ev.nobjs();
1638  int n_measured_vars = nobjs * 3;
1639  int n_unmeasured_vars = 0;
1640  int n_constraints = _constraints.size();
1641 
1642  if (use_kt) {
1643  n_measured_vars += 2;
1644 
1645  if (ev.has_neutrino())
1646  n_unmeasured_vars = 1;
1647  else
1648  n_constraints += 2;
1649  }
1650 
1651  Matrix G_i(n_measured_vars, n_measured_vars);
1652  Diagonal_Matrix Y(n_unmeasured_vars);
1653  Column_Vector x(n_measured_vars);
1654  Column_Vector y(n_unmeasured_vars);
1655  pack_event(ev, _args.use_e(), use_kt, x, y, G_i, Y);
1656 
1657  Column_Vector xm = x;
1658  Column_Vector ym = y;
1659 
1660  // ??? Should allow for using a different underlying fitter here.
1662 
1664 
1665  Matrix Q;
1666  Matrix R;
1667  Matrix S;
1668  double chisq = fitter.fit(cc, xm, x, ym, y, G_i, Y, pullx, pully, Q, R, S);
1669 
1670  unpack_event(ev, x, y, _args.use_e(), use_kt);
1671 
1672  calculate_mass(ev, _mass_constraint, _args, chisq, Q, R, S, m, sigm);
1673 
1674  return chisq;
1675  }
1676 
1677 } // namespace hitfit
tuple base
Main Program
Definition: newFWLiteAna.py:92
const edm::EventSetup & c
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:73
const TString p2
Definition: fwPaths.cc:13
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:119
Represent an event for kinematic fitting as a collection of four-momenta. Each object is represented ...
double sign(double x)
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:63
bool ev
Exp< T >::type exp(const T &t)
Definition: Exp.h:22
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.
assert(be >=bs)
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:62
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:19
if(conf_.getParameter< bool >("UseStripCablingDB"))
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:55
const TString p1
Definition: fwPaths.cc:12
const Chisq_Constrainer_Args & chisq_constrainer_args() const
Hold on to parameters for the Chisq_Constrainer class.
const Fourvec_Constrainer_Args _args
void adjust_p_for_mass(Fourvec &v, double mass)
Adjust the three-vector part of v, leaving the energy unchanged,.
Definition: fourvec.cc:95
std::vector< Constraint > _mass_constraint
Fourvec_Constraint_Calculator(Fourvec_Event &ev, const vector< Constraint > &constraints, const Fourvec_Constrainer_Args &args)
Constructor.
CLHEP::HepDiagMatrix Diagonal_Matrix
Definition: matutil.h:64
A lookup table to speed up constraint evaluation using Fourvec_Constrainer.
Definition: Pair_Table.h:95
bool eval(const Column_Vector &x, const Column_Vector &y, Row_Vector &F, Matrix &Bx, Matrix &By) override
Evaluate constraints at the point described by x and y (well-measured and poorly-measured variables...
double S(const TLorentzVector &, const TLorentzVector &)
Definition: Particle.cc:97
Chisq_Constrainer_Args _chisq_constrainer_args
std::vector< Constraint > _constraints
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...
Define an interface for getting parameter settings.
Definition: Defaults.h:57
std::ostream & operator<<(std::ostream &s, const Constraint_Intermed &ci)
Output stream operator, print the content of this Constraint_Intermed to an output stream...
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...
Represent a single object in a Fourvec_Event, this is just a dumb data container. Each object in a Fo...
Definition: Fourvec_Event.h:90
static uInt32 F(BLOWFISH_CTX *ctx, uInt32 x)
Definition: blowfish.cc:163
tmp
align.sh
Definition: createJobs.py:716
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.
tuple size
Write out results.
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:79
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:166
Represent an event for kinematic fitting as a collection of four-momenta.
bool has_neutrino() const
Return TRUE is this event contains a neutrino, otherwise returns FALSE.