CMS 3D CMS Logo

ProtonReconstructionAlgorithm.cc
Go to the documentation of this file.
1 /****************************************************************************
2  * Authors:
3  * Jan Kašpar
4  * Laurent Forthomme
5  ****************************************************************************/
6 
8 
10 
14 
15 #include "TMinuitMinimizer.h"
16 
17 using namespace std;
18 using namespace edm;
19 
20 //----------------------------------------------------------------------------------------------------
21 
22 ProtonReconstructionAlgorithm::ProtonReconstructionAlgorithm(bool fit_vtx_y, bool improved_estimate, unsigned int verbosity) :
23  verbosity_(verbosity),
24  fitVtxY_(fit_vtx_y),
25  useImprovedInitialEstimate_(improved_estimate),
26  initialized_(false),
27  fitter_(new ROOT::Fit::Fitter), chiSquareCalculator_(new ChiSquareCalculator)
28 {
29  // needed for thread safety
30  TMinuitMinimizer::UseStaticMinuit(false);
31 
32  // initialise fitter
33  double pStart[] = { 0, 0, 0, 0 };
34  fitter_->SetFCN(4, *chiSquareCalculator_, pStart, 0, true);
35 }
36 
37 //----------------------------------------------------------------------------------------------------
38 
40 {
41  // reset cache
42  release();
43 
44  // build optics data for each object
45  for (const auto &p : opticalFunctions)
46  {
47  const LHCInterpolatedOpticalFunctionsSet &ofs = p.second;
48 
49  // make record
50  RPOpticsData rpod;
51  rpod.optics = &p.second;
55 
56  vector<double> xiValues = ofs.getXiValues(); // local copy made since the TSpline constructor needs non-const parameters
57  vector<double> xDValues = ofs.getFcnValues()[LHCOpticalFunctionsSet::exd];
58  rpod.s_xi_vs_x_d = make_shared<TSpline3>("", xDValues.data(), xiValues.data(), xiValues.size());
59 
60  // calculate auxiliary data
61  LHCInterpolatedOpticalFunctionsSet::Kinematics k_in = { 0., 0., 0., 0., 0. };
63  rpod.optics->transport(k_in, k_out);
64  rpod.x0 = k_out.x;
65  rpod.y0 = k_out.y;
66 
68  rpod.ch0 -= rpod.x0;
69 
71 
72  // insert record
73  const CTPPSDetId rpId(p.first);
74  m_rp_optics_.emplace(rpId, std::move(rpod));
75  }
76 
77  // update settings
78  initialized_ = true;
79 }
80 
81 //----------------------------------------------------------------------------------------------------
82 
83 void ProtonReconstructionAlgorithm::doLinearFit(const std::vector<double> &vx, const std::vector<double> &vy, double &b, double &a)
84 {
85  double s_1=0., s_x=0., s_xx=0., s_y=0., s_xy=0.;
86  for (unsigned int i = 0; i < vx.size(); ++i)
87  {
88  s_1 += 1.;
89  s_x += vx[i];
90  s_xx += vx[i] * vx[i];
91  s_y += vy[i];
92  s_xy += vx[i] * vy[i];
93  }
94 
95  const double d = s_xx * s_1 - s_x * s_x;
96  a = ( s_1 * s_xy - s_x * s_y) / d;
97  b = (-s_x * s_xy + s_xx * s_y) / d;
98 }
99 
100 //----------------------------------------------------------------------------------------------------
101 
103 {
104  initialized_ = false;
105 
106  m_rp_optics_.clear();
107 }
108 
109 //----------------------------------------------------------------------------------------------------
110 
112 {
113  // extract proton parameters
114  const LHCInterpolatedOpticalFunctionsSet::Kinematics k_in = { 0., parameters[1], parameters[3], parameters[2], parameters[0] };
115 
116  // calculate chi^2 by looping over hits
117  double s2 = 0.;
118 
119  for (const auto &track : *tracks) {
120  const CTPPSDetId rpId(track->getRPId());
121 
122  // transport proton to the RP
123  auto oit = m_rp_optics->find(rpId);
125  oit->second.optics->transport(k_in, k_out);
126 
127  // proton position wrt. beam
128  const double x = k_out.x - oit->second.x0;
129  const double y = k_out.y - oit->second.y0;
130 
131  // calculate chi^2 contributions, convert track data mm --> cm
132  const double x_diff_norm = (x - track->getX()*1E-1) / (track->getXUnc()*1E-1);
133  const double y_diff_norm = (y - track->getY()*1E-1) / (track->getYUnc()*1E-1);
134 
135  // increase chi^2
136  s2 += x_diff_norm*x_diff_norm + y_diff_norm*y_diff_norm;
137  }
138 
139  return s2;
140 }
141 
142 //----------------------------------------------------------------------------------------------------
143 
145  const LHCInfo& lhcInfo, std::ostream& os) const
146 {
147  // make sure optics is available for all tracks
148  for (const auto &it : tracks) {
149  auto oit = m_rp_optics_.find(it->getRPId());
150  if (oit == m_rp_optics_.end())
151  throw cms::Exception("ProtonReconstructionAlgorithm") << "Optics data not available for RP " <<
152  it->getRPId() << ", i.e. " << CTPPSDetId(it->getRPId()) << ".";
153  }
154 
155  // initial estimate of xi and th_x
156  double xi_init = 0., th_x_init = 0.;
157 
159  double x_N = tracks[0]->getX()*1E-1, // conversion: mm --> cm
160  x_F = tracks[1]->getX()*1E-1;
161 
162  const RPOpticsData &i_N = m_rp_optics_.find(tracks[0]->getRPId())->second,
163  &i_F = m_rp_optics_.find(tracks[1]->getRPId())->second;
164 
165  const double a = i_F.ch1*i_N.la1 - i_N.ch1*i_F.la1;
166  const double b = i_F.ch0*i_N.la1 - i_N.ch0*i_F.la1 + i_F.ch1*i_N.la0 - i_N.ch1*i_F.la0 + x_N*i_F.la1 - x_F*i_N.la1;
167  const double c = x_N*i_F.la0 - x_F*i_N.la0 + i_F.ch0*i_N.la0 - i_N.ch0*i_F.la0;
168  const double D = b*b - 4.*a*c;
169  const double sqrt_D = (D >= 0.) ? sqrt(D) : 0.;
170 
171  xi_init = (-b + sqrt_D) / 2. / a;
172  th_x_init = (x_N - i_N.ch0 - i_N.ch1 * xi_init) / (i_N.la0 + i_N.la1 * xi_init);
173  }
174  else {
175  double s_xi0 = 0., s_1 = 0.;
176  for (const auto &track : tracks) {
177  auto oit = m_rp_optics_.find(track->getRPId());
178  double xi = oit->second.s_xi_vs_x_d->Eval(track->getX()*1E-1 + oit->second.x0); // conversion: mm --> cm
179 
180  s_1 += 1.;
181  s_xi0 += xi;
182  }
183 
184  xi_init = s_xi0 / s_1;
185  }
186 
187  if (!std::isfinite(xi_init))
188  xi_init = 0.;
189  if (!std::isfinite(th_x_init))
190  th_x_init = 0.;
191 
192  // initial estimate of th_y and vtx_y
193  double y[2]={0}, v_y[2]={0}, L_y[2]={0};
194  unsigned int y_idx = 0;
195  for (const auto &track : tracks) {
196  if (y_idx >= 2) break;
197 
198  auto oit = m_rp_optics_.find(track->getRPId());
199 
200  y[y_idx] = track->getY()*1E-1 - oit->second.s_y_d_vs_xi->Eval(xi_init); // track y: mm --> cm
201  v_y[y_idx] = oit->second.s_v_y_vs_xi->Eval(xi_init);
202  L_y[y_idx] = oit->second.s_L_y_vs_xi->Eval(xi_init);
203 
204  y_idx++;
205  }
206 
207  double vtx_y_init = 0.;
208  double th_y_init = 0.;
209 
210  if (fitVtxY_) {
211  const double det_y = v_y[0] * L_y[1] - L_y[0] * v_y[1];
212  vtx_y_init = (det_y != 0.) ? (L_y[1] * y[0] - L_y[0] * y[1]) / det_y : 0.;
213  th_y_init = (det_y != 0.) ? (v_y[0] * y[1] - v_y[1] * y[0]) / det_y : 0.;
214  }
215  else {
216  vtx_y_init = 0.;
217  th_y_init = (y[1]/L_y[1] + y[0]/L_y[0]) / 2.;
218  }
219 
220  if (!std::isfinite(vtx_y_init))
221  vtx_y_init = 0.;
222  if (!std::isfinite(th_y_init))
223  th_y_init = 0.;
224 
225  unsigned int armId = CTPPSDetId((*tracks.begin())->getRPId()).arm();
226 
227  if (verbosity_)
228  os
229  << "ProtonReconstructionAlgorithm::reconstructFromMultiRP(" << armId << ")" << std::endl
230  << " initial estimate: xi_init = " << xi_init << ", th_x_init = " << th_x_init
231  << ", th_y_init = " << th_y_init << ", vtx_y_init = " << vtx_y_init << "." << std::endl;
232 
233  // minimisation
234  fitter_->Config().ParSettings(0).Set("xi", xi_init, 0.005);
235  fitter_->Config().ParSettings(1).Set("th_x", th_x_init, 2E-6);
236  fitter_->Config().ParSettings(2).Set("th_y", th_y_init, 2E-6);
237  fitter_->Config().ParSettings(3).Set("vtx_y", vtx_y_init, 10E-6);
238 
239  if (!fitVtxY_)
240  fitter_->Config().ParSettings(3).Fix();
241 
242  chiSquareCalculator_->tracks = &tracks;
243  chiSquareCalculator_->m_rp_optics = &m_rp_optics_;
244 
245  fitter_->FitFCN();
246  fitter_->FitFCN(); // second minimisation in case the first one had troubles
247 
248  // extract proton parameters
249  const ROOT::Fit::FitResult& result = fitter_->Result();
250  const double *params = result.GetParams();
251 
252  if (verbosity_)
253  os
254  << " fit valid=" << result.IsValid()
255  << std::endl
256  << " xi=" << params[0] << " +- " << result.Error(0)
257  << ", th_x=" << params[1] << " +-" << result.Error(1)
258  << ", th_y=" << params[2] << " +-" << result.Error(2)
259  << ", vtx_y=" << params[3] << " +-" << result.Error(3)
260  << ", chiSq = " << result.Chi2() << std::endl;
261 
262  // save reco candidate
263  using FP = reco::ForwardProton;
264 
265  const double sign_z = (armId == 0) ? +1. : -1.; // CMS convention
266  const FP::Point vertex(0., params[3], 0.);
267  const double xi = params[0];
268  const double th_x = params[1];
269  const double th_y = params[2];
270  const double cos_th = sqrt(1. - th_x*th_x - th_y*th_y);
271  const double p = lhcInfo.energy() * (1. - xi);
272  const FP::Vector momentum(
273  - p * th_x, // the signs reflect change LHC --> CMS convention
274  + p * th_y,
275  sign_z * p * cos_th
276  );
277  signed int ndf = 2.*tracks.size() - ((fitVtxY_) ? 4. : 3.);
278 
279  map<unsigned int, signed int> index_map = {
280  {(unsigned int) FP::Index::xi, 0},
281  {(unsigned int) FP::Index::th_x, 1},
282  {(unsigned int) FP::Index::th_y, 2},
283  {(unsigned int) FP::Index::vtx_y, ((fitVtxY_) ? 3 : -1)},
284  {(unsigned int) FP::Index::vtx_x, -1},
285  };
286 
288  for (unsigned int i = 0; i < (unsigned int) FP::Index::num_indices; ++i) {
289  signed int fit_i = index_map[i];
290 
291  for (unsigned int j = 0; j < (unsigned int) FP::Index::num_indices; ++j) {
292  signed int fit_j = index_map[j];
293 
294  cm(i, j) = (fit_i >= 0 && fit_j >= 0) ? result.CovMatrix(fit_i, fit_j) : 0.;
295  }
296  }
297 
298  return reco::ForwardProton(result.Chi2(), ndf, vertex, momentum, xi, cm,
299  FP::ReconstructionMethod::multiRP, tracks, result.IsValid());
300 }
301 
302 //----------------------------------------------------------------------------------------------------
303 
305  const LHCInfo& lhcInfo, std::ostream& os) const
306 {
307  CTPPSDetId rpId(track->getRPId());
308 
309  if (verbosity_)
310  os << "reconstructFromSingleRP(" << rpId.arm()*100 + rpId.station()*10 + rpId.rp() << ")" << std::endl;
311 
312  // make sure optics is available for the track
313  auto oit = m_rp_optics_.find(track->getRPId());
314  if (oit == m_rp_optics_.end())
315  throw cms::Exception("ProtonReconstructionAlgorithm") << "Optics data not available for RP " << track->getRPId()
316  << ", i.e. " << rpId << ".";
317 
318  // rough estimate of xi and th_y from each track
319  const double x_full = track->getX()*1E-1 + oit->second.x0; // conversion mm --> cm
320  const double xi = oit->second.s_xi_vs_x_d->Eval(x_full);
321  const double L_y = oit->second.s_L_y_vs_xi->Eval(xi);
322  const double th_y = track->getY()*1E-1 / L_y; // conversion mm --> cm
323 
324  const double ep_x = 1E-6;
325  const double dxi_dx = (oit->second.s_xi_vs_x_d->Eval(x_full + ep_x) - xi) / ep_x;
326  const double xi_unc = abs(dxi_dx) * track->getXUnc() * 1E-1; // conversion mm --> cm
327 
328  const double ep_xi = 1E-4;
329  const double dL_y_dxi = ( oit->second.s_L_y_vs_xi->Eval(xi + ep_xi) - L_y ) / ep_xi;
330  const double th_y_unc = th_y * sqrt( pow(track->getYUnc() / track->getY(), 2.) + pow(dL_y_dxi * xi_unc / L_y, 2.) );
331 
332  if (verbosity_)
333  os << " xi = " << xi << " +- " << xi_unc << ", th_y = " << th_y << " +- " << th_y_unc << "." << std::endl;
334 
335  using FP = reco::ForwardProton;
336 
337  // save proton candidate
338  const double sign_z = (CTPPSDetId(track->getRPId()).arm() == 0) ? +1. : -1.; // CMS convention
339  const FP::Point vertex(0., 0., 0.);
340  const double cos_th = sqrt(1. - th_y*th_y);
341  const double p = lhcInfo.energy() * (1. - xi);
342  const FP::Vector momentum(0., p * th_y, sign_z * p * cos_th);
343 
345  cm((int)FP::Index::xi, (int)FP::Index::xi) = xi_unc * xi_unc;
346  cm((int)FP::Index::th_y, (int)FP::Index::th_y) = th_y_unc * th_y_unc;
347 
349  trk.push_back( track );
350 
351  return reco::ForwardProton(0., 0, vertex, momentum, xi, cm, FP::ReconstructionMethod::singleRP, trk, true);
352 }
353 
std::unique_ptr< ROOT::Fit::Fitter > fitter_
fitter object
ROOT::Math::Plane3D::Vector Vector
Definition: EcalHitMaker.cc:29
reco::ForwardProton reconstructFromSingleRP(const CTPPSLocalTrackLiteRef &track, const LHCInfo &lhcInfo, std::ostream &os) const
run proton reconstruction using single-RP strategy
math::Error< 5 >::type CovarianceMatrix
const std::vector< double > & getXiValues() const
std::pair< double, double > Point
Definition: CaloEllipse.h:18
std::map< unsigned int, RPOpticsData > m_rp_optics_
map: RP id –> optics data
void init(const LHCInterpolatedOpticalFunctionsSetCollection &opticalFunctions)
const std::vector< std::shared_ptr< const TSpline3 > > & splines() const
std::unique_ptr< ChiSquareCalculator > chiSquareCalculator_
object to calculate chi^2
double ch0
intercept for linear approximation of
Definition: Fit.h:34
T sqrt(T t)
Definition: SSEVec.h:18
double la1
slope for linear approximation of
reco::ForwardProton reconstructFromMultiRP(const CTPPSLocalTrackLiteRefVector &tracks, const LHCInfo &lhcInfo, std::ostream &os) const
run proton reconstruction using multiple-RP strategy
static void doLinearFit(const std::vector< double > &vx, const std::vector< double > &vy, double &b, double &a)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double la0
intercept for linear approximation of
void transport(const Kinematics &input, Kinematics &output, bool calculateAngles=false) const
transports proton according to the splines
DecomposeProduct< arg, typename Div::arg > D
Definition: Factorize.h:152
Set of optical functions corresponding to one scoring plane along LHC, including splines for interpol...
ProtonReconstructionAlgorithm(bool fit_vtx_y, bool improved_estimate, unsigned int verbosity)
double b
Definition: hdecay.h:120
Base class for CTPPS detector IDs.
Definition: CTPPSDetId.h:32
HLT enums.
double a
Definition: hdecay.h:121
float const energy() const
Definition: LHCInfo.cc:192
void push_back(value_type const &ref)
Add a Ref<C, T> to the RefVector.
Definition: RefVector.h:69
const LHCInterpolatedOpticalFunctionsSet * optics
double ch1
slope for linear approximation of
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
const std::vector< std::vector< double > > & getFcnValues() const
def move(src, dest)
Definition: eostools.py:511