StFms  0.0.0
FMS software in the STAR framework
StFmsClusterFitter.cxx
Go to the documentation of this file.
1 // $Id$
2 //
3 // $Log$
14 
15 #include <vector>
16 
17 #include "TF2.h"
18 #include "TMath.h"
19 
20 #include "StRoot/St_base/StMessMgr.h"
21 #include "StEvent/StFmsHit.h"
22 
25 
26 namespace {
27 const Int_t kNFitParameters = 10;
28 TF2 showerShapeFitFunction("showerShapeFitFunction",
30  -25.0, 25.0, -25.0, 25.0, kNFitParameters);
31 } // unnamed namespace
32 
33 namespace FMSCluster {
34 // Instantiate static members
37 
39  Int_t detectorId)
40  : mMinuit(3 * kMaxNPhotons + 1) {
41  // Set steps for Minuit fitting
42  const Double_t step[3 * kMaxNPhotons + 1]= {
43  0.0, 0.1, 0.1, 0.2, 0.1, 0.1, 0.2, 0.1, 0.1, 0.2, 0.1,
44  0.1, 0.2, 0.1, 0.1, 0.2, 0.1, 0.1, 0.2, 0.1, 0.1, 0.2
45  };
46  for (int j = 0; j < 3 * kMaxNPhotons + 1; j++) {
47  mSteps[j] = step[j];
48  } // for
49  std::vector<Float_t> towerWidth = geometry->towerWidths(detectorId);
50  mTowerWidth = towerWidth[0];
51  StFmsClusterFitter::mTowerWidthXY[0] = towerWidth[0];
52  StFmsClusterFitter::mTowerWidthXY[1] = towerWidth[1];
53  Double_t para[kNFitParameters];
54  para[0] = mTowerWidth;
55  para[1] = 1.070804;
56  para[2] = 0.167773;
57  para[3] = -0.238578;
58  para[4] = 0.535845;
59  para[5] = 0.850233;
60  para[6] = 2.382637;
61  para[7] = 0.0;
62  para[8] = 0.0;
63  para[9] = 1.0;
64  showerShapeFitFunction.SetParameters(para);
65  // create a Minuit instance
66  mMinuit.SetPrintLevel(-1); // Quiet, including suppression of warnings
67 }
68 
70 
72  return &showerShapeFitFunction;
73 }
74 
75 Double_t StFmsClusterFitter::fit(const Double_t* para, const Double_t* step,
76  const Double_t* low, const Double_t* up,
77  PhotonList* photons) {
78  if (!step) {
79  step = mSteps;
80  } // if
81  Double_t chiSq(-1.); // Return value
82  // Check that there is a pointer to TObjArray of towers
84  LOG_ERROR << "no tower data available! return -1!" << endm;
85  return chiSq;
86  } // if
88  Int_t nPh = (Int_t)para[0]; // Get the number of photons from parameters
89  if (nPh < 1 || nPh > kMaxNPhotons) {
90  LOG_ERROR << "nPh = " << nPh << "! Number of photons must be between 1 and "
91  << kMaxNPhotons << "! Set it to be 1!" << endm;
92  nPh = 1;
93  } // if
94  mMinuit.mncler(); // Clear old parameters so we can define the new parameters
95  // The first parameter tells Minuit how many photons to fit!
96  // It should be a fixed parameter, and between 1 and the max number of photons
97  Int_t ierflg = 0;
98  Double_t nPhotons(nPh); // Minuit needs a double argument
99  mMinuit.mnparm(0, "nph", nPhotons, 0, 0.5, 4.5, ierflg);
100  // Set the rest of parameters: 3 parameters per photon
101  for (Int_t i = 0; i < nPh; i++) {
102  Int_t j = 3 * i + 1; // Need to set 3 parameters per photon
103  mMinuit.mnparm(j, Form("x%d", i + 1),
104  para[j], step[j], low[j], up[j], ierflg);
105  j++;
106  mMinuit.mnparm(j, Form("y%d", i + 1),
107  para[j], step[j], low[j], up[j], ierflg);
108  j++;
109  mMinuit.mnparm(j, Form("E%d", i + 1),
110  para[j], step[j], low[j], up[j], ierflg);
111  } // if
112  Double_t arglist[10];
113  arglist[0] = 1000;
114  arglist[1] = 1.;
115  ierflg = 0;
116  mMinuit.mnexcm("MIGRAD", arglist, 2, ierflg);
117  // Populate the list of photons
118  if (0 == mMinuit.GetStatus() && photons) {
119  // Get the fit results for starting positions and errors
120  Double_t param[1 + 3 * kMaxNPhotons];
121  Double_t error[1 + 3 * kMaxNPhotons];
122  mMinuit.GetParameter(0, param[0], error[0]);
123  // There are 3 parameters per photon, plus the 1st parameter
124  nPh = (Int_t)param[0]; // Shouldn't have changed, but just to be safe...
125  const Int_t nPar = 3 * nPh + 1;
126  for (Int_t i(1); i < nPar; ++i) { // Get remaining fit parameters (x, y, E)
127  mMinuit.GetParameter(i, param[i], error[i]);
128  } // for
129  for (Int_t par(1); par < nPar; par += 3) { // Fill photons from parameters
130  photons->push_back( // x, y, E, error x, error y, error E
131  StFmsFittedPhoton(param[par], param[par + 1], param[par + 2],
132  error[par], error[par + 1], error[par + 2]));
133  } // for
134  // Evaluate chi-square (*not* chi-square per degree of freedom)
135  Int_t iflag = 1; // Don't calculate 1st derivatives, 2nd argument unneeded
136  mMinuit.Eval(photons->size(), NULL, chiSq, param, iflag);
137  } // for
138  return chiSq;
139 }
140 
141 /*
142  A different set of parameters for 2-photon clusters only:
143  0: still a constant parameter, should be set to 2 for 2-photon fitting
144  1: xPi, x-position of pi^0
145  2: yPi, y-position of pi^0
146  3: d_gg, distance between 2 photons
147  4: theta, angle of displacement vector from photon 2 to photon 1
148  5: z_gg, can go from -1 to +1, so we do not set E1 > E2
149  6: E_gg, total energy of two photons
150  Thus, in the more conventional fit() parameterization: x1, y1, E1, x2, y2, E2:
151  E1 = E_gg * (1 + z_gg) / 2
152  E2 = E_gg * (1 - z_gg) / 2
153  x1 = xPi + cos(theta) * d_gg * (1 - z_gg) / 2
154  y1 = yPi + sin(theta) * d_gg * (1 - z_gg) / 2
155  x2 = xPi - cos(theta) * d_gg * (1 + z_gg) / 2
156  y2 = yPi - sin(theta) * d_gg * (1 + z_gg) / 2
157 
158  The advantage of this parameterization is that for 2-photon cluster fitting
159  we can ensure that the two photons never get to close. The old parameterization
160  suffers from this shortcoming if we let the parameters vary freely.
161 
162  What we already know about the limits of the new parameters:
163  xPi and yPi: rarely do they go beyond 0.3 unit of lgd
164  theta: have a narrow theta range (for r = sigmaMax / sigmaMax,
165  |theta| < 0.5 * r / 0.65 when r < 0.65, and linear increase
166  from 0.5 to pi/2 for 0.65 < r < 1)
167  E_gg: given by Ec (+/- 20% or less)
168  z_gg: should just let it vary from -1 to 1
169  d_gg: a lower bound is given by r = sqrt(sigmaX^2 + sigmaY^2).
170  d_gg > Max(2.5 * (r - 0.6), 0.5)
171  */
172 Int_t StFmsClusterFitter::fit2PhotonCluster(const Double_t* para,
173  const Double_t* step,
174  const Double_t* low,
175  const Double_t* up,
176  PhotonList* photons) {
177  if (!step) {
178  step = mSteps;
179  } // if
180  Double_t chiSq(-1.); // Return value
181  // Check that there is a pointer to TObjArray of towers
183  LOG_ERROR << "no tower data available! return -1!" << endm;
184  return chiSq;
185  } // if
187  Int_t nPh = (Int_t)para[0];
188  if (nPh != 2) {
189  LOG_ERROR << "number of photons must be 2 for special 2-photon cluster "
190  << "fitter \"Int_t StFmsClusterFitter::fit2PhotonCluster(...)\"!"
191  << " Set it to be 2!" << endm;
192  nPh = 2;
193  } // if
194  mMinuit.mncler(); // Clear old parameters so we can define the new parameters
195  // The first parameter tells Minuit how many photons to fit!
196  // It should be a fixed parameter, in this case 2
197  Int_t ierflg = 0;
198  Double_t nPhotons(nPh); // Minuit needs a double argument
199  mMinuit.mnparm(0, "nph", nPhotons, 0, 1.5, 2.5, ierflg);
200  mMinuit.mnparm(1, "xPi" , para[1], step[1], low[1], up[1], ierflg);
201  mMinuit.mnparm(2, "yPi" , para[2], step[2], low[2], up[2], ierflg);
202  mMinuit.mnparm(3, "d_gg" , para[3], step[3], low[3], up[3], ierflg);
203  mMinuit.mnparm(4, "theta", para[4], step[4], low[4], up[4], ierflg);
204  mMinuit.mnparm(5, "z_gg" , para[5], step[5], low[5], up[5], ierflg);
205  mMinuit.mnparm(6, "E_gg" , para[6], step[6], low[6], up[6], ierflg);
206  // Fix E_total and theta, we don't want these to be free parameters
207  mMinuit.FixParameter(6);
208  mMinuit.FixParameter(4);
209  Double_t arglist[10];
210  arglist[0] = 1000;
211  arglist[1] = 1.;
212  ierflg = 0;
213  mMinuit.mnexcm("MIGRAD", arglist, 2, ierflg);
214  mMinuit.mnfree(0); // Free fixed parameters before next use of mMinuit
215  if (0 == mMinuit.GetStatus() && photons) {
216  // Get the fit results
217  Double_t param[7]; // 3 * nPhotons + 1 parameters = 7 for 2 photons
218  Double_t error[7];
219  mMinuit.GetParameter(0, param[0], error[0]);
220  Int_t nPar = 3 * (Int_t)param[0] + 1; // Should be 7
221  for (Int_t ipar = 1; ipar < nPar; ipar++) { // Get the remaining parameters
222  mMinuit.GetParameter(ipar, param[ipar], error[ipar]);
223  } // for
224  // Put the fit result back in "clust". Need to translate the special
225  // parameters for 2-photon fit into x, y, E, which looks a bit complicated!
226  // First photons
227  double x = param[1] + cos(param[4]) * param[3] * (1 - param[5]) / 2.0;
228  double xErr = error[1] +
229  (cos(param[4]) * error[3] - error[4] * sin(param[4]) * param[3]) *
230  (1 - param[5]) / 2 - cos(param[4]) * param[3] * error[5] / 2.0;
231  double y = param[2] + sin(param[4]) * param[3] * (1 - param[5]) / 2.0;
232  double yErr = error[2] +
233  (sin(param[4]) * error[3] + error[4] * cos(param[4]) * param[3]) *
234  (1 - param[5]) / 2 - sin(param[4]) * param[3] * error[5] / 2.0;
235  double E = param[6] * (1 + param[5]) / 2.0;
236  double EErr = error[6] * (1 + param[5]) / 2.0 + param[6] * error[5] / 2.0;
237  photons->push_back(StFmsFittedPhoton(x, y, E, xErr, yErr, EErr));
238  // Second photon
239  x = param[1] - cos(param[4]) * param[3] * (1 + param[5]) / 2.0;
240  xErr = error[1] +
241  (-cos(param[4]) * error[3] + error[4] * sin(param[4]) * param[3]) *
242  (1 + param[5]) / 2 - cos(param[4]) * param[3] * error[5] / 2.0;
243  y = param[2] - sin(param[4]) * param[3] * (1 + param[5]) / 2.0;
244  yErr = error[2] +
245  (sin(param[4]) * error[3] - error[4] * cos(param[4]) * param[3]) *
246  (1 + param[5]) / 2 - sin(param[4]) * param[3] * error[5] / 2.0;
247  E = param[6] * (1 - param[5]) / 2.0;
248  EErr = error[6] * (1 - param[5]) / 2.0 - param[6] * error[5] / 2.0;
249  photons->push_back(StFmsFittedPhoton(x, y, E, xErr, yErr, EErr));
250  // Evaluate the Chi-square function
251  Int_t iflag = 1; // Don't calculate 1st derivatives...
252  mMinuit.Eval(7, NULL, chiSq, param, iflag); // ... so 2nd argument unneeded
253  } // if
254  return chiSq;
255 }
256 
257 // xy array contains (x, y) position of the photon relative to the tower center
259  Double_t* para) {
260  Double_t gg(0);
261  // Calculate the energy deposited in a tower
262  // Evaluate energyDepositionDistribution at x+/-d/2 and y+/-d/2, for tower
263  // width d. The double-loop below is equivalent to
264  // F(x+d/2, y+d/2) + F(x-d/2, y-d/2) - F(x-d/2, y+d/2) - F(x+d/2, y-d/2)
265  for (Int_t ix = 0; ix < 2; ix++) {
266  for (Int_t iy = 0; iy < 2; iy++) {
267  Double_t signX = pow(-1.0, ix); // 1 or -1
268  Double_t signY = pow(-1.0, iy); // 1 or -1
269  // para[0] is the cell width
270  // para[7] and para[8] are offsets that are normally zero
271  Double_t s[2];
272  s[0] = xy[0] - para[7] + signX * para[0] / 2.0; // x +/- d/2
273  s[1] = xy[1] - para[8] + signY * para[0] / 2.0; // y +/- d/2
274  gg += signX * signY * energyDepositionDistribution(s, para);
275  } // for
276  } // for
277  return gg * para[9];
278 }
279 
280 // Calculate fractional photon energy deposition in a tower based on its (x, y)
281 // position relative to the tower center
283  Double_t* xy,
284  Double_t* parameters) {
285  Double_t f = 0;
286  Double_t x = xy[0];
287  Double_t y = xy[1];
288  for (Int_t i = 1; i <= 3; i++) {
289  // The parameter array has 10 elements, but we only use 6
290  // Parameters 1 to 6 are a1, a2, a3, b1, b2, b3 as defined in
291  // https://drupal.star.bnl.gov/STAR/blog/leun/2010/aug/02/fms-meeting-20100802
292  Double_t a = parameters[i];
293  Double_t b = parameters[i + 3];
294  f += a * atan(x * y / (b * sqrt(b * b + x * x + y * y)));
295  } // for
296  return f / TMath::TwoPi();
297 }
298 
299 // Uses the signature needed for TMinuit interface:
300 // http://root.cern.ch/root/htmldoc/TMinuit.html#TMinuit:SetFCN
302  Double_t* grad,
303  Double_t& fval,
304  Double_t* para,
305  Int_t iflag) {
306  // Number of expected photons should ALWAYS be the first parameter "para[0]"
307  Int_t numbPh = (Int_t)para[0];
308  // Sum energy of all towers being studied
309  Double_t sumCl = 0;
310  typedef StFmsTowerCluster::Towers::const_iterator TowerIter;
311  for (TowerIter i = mTowers->begin(); i != mTowers->end(); ++i) {
312  sumCl += (*i)->hit()->energy();
313  } // for
314  // Loop over all towers that are involved in the fit
315  fval = 0; // Stores sum of chi2 over each tower
316  for (TowerIter i = mTowers->begin(); i != mTowers->end(); ++i) {
317  const StFmsTower* tower = *i;
318  // The shower shape function expects the centers of towers in units of cm
319  // Tower centers are stored in row/column i.e. local coordinates
320  // Therefore convert to cm, remembering to subtract 0.5 from row/column to
321  // get centres not edges
322  const Double_t x = (tower->column() - 0.5) *
324  const Double_t y = (tower->row() - 0.5) *
326  // Measured energy
327  const Double_t eMeas = tower->hit()->energy();
328  // Expected energy from Shower-Shape
329  Double_t eSS = 0;
330  for (Int_t iph = 0; iph < numbPh; iph++) {
331  Int_t j = 3 * iph;
332  Double_t Eshape = para[j + 3] *
333  showerShapeFitFunction.Eval(x - para[j + 1],
334  y - para[j + 2], 0);
335  eSS += Eshape;
336  } // for
337  const Double_t dev = eMeas - eSS;
338  const Double_t errFactor = 0.03;
339  const Double_t errQ = 0.01;
340  // Larisa's Chi2 function
341  const Double_t err = (errFactor * pow(eMeas / sumCl, 1. - 0.001 * sumCl) *
342  pow(1 - eMeas / sumCl, 1. - 0.007 * sumCl)) * sumCl
343  + errQ;
344  const Double_t dchi2 = dev * dev / err; // Calculate chi^2 of this tower
345  fval += dchi2; // Add chi2 for this tower to the sum
346  } // for
347  // require that the fraction be positive!
348  if (fval < 0) {
349  fval = 0;
350  } // if
351 }
352 
353 // Uses the signature needed for TMinuit interface:
354 // http://root.cern.ch/root/htmldoc/TMinuit.html#TMinuit:SetFCN
356  Double_t* grad,
357  Double_t& fval,
358  Double_t* param,
359  Int_t iflag) {
360  // Only need to translate into the old parameterization
361  Double_t oldParam[7];
362  float dd = param[3];
363  oldParam[0] = param[0]; // Number of photons, unchanged
364  oldParam[1] = param[1] + cos(param[4]) * dd * (1 - param[5]) / 2.0; // x 1
365  oldParam[2] = param[2] + sin(param[4]) * dd * (1 - param[5]) / 2.0; // y 1
366  oldParam[3] = param[6] * (1 + param[5]) / 2.0; // Energy 1
367  oldParam[4] = param[1] - cos(param[4]) * dd * (1 + param[5]) / 2.0; // x 2
368  oldParam[5] = param[2] - sin(param[4]) * dd * (1 + param[5]) / 2.0; // y 2
369  oldParam[6] = param[6] * (1 - param[5]) / 2.0; // Energy 2
370  // Now call the regular minimization function with the translated parameters
371  minimizationFunctionNPhoton(nparam, grad, fval, oldParam, iflag);
372 }
373 } // namespace FMSCluster
static const Int_t kMaxNPhotons
Maximum number that can be fitted.
static Double_t energyDepositionDistribution(Double_t *x, Double_t *par)
Declaration of StFmsGeometry, an FMS database geometry interface.
Double_t fit(const Double_t *par, const Double_t *step, const Double_t *low, const Double_t *up, PhotonList *photons)
static Double_t energyDepositionInTower(Double_t *x, Double_t *par)
TMinuit mMinuit
Minuit fitting interface.
Declaration of StFmsTower, a simple FMS tower wrapper.
Int_t column() const
Definition: StFmsTower.h:82
Declaration of StFmsClusterFitter, shower-shape fitting routine.
std::list< StFmsTower * > Towers
Shorthand for tower collection.
Double_t mSteps[3 *kMaxNPhotons+1]
Step size in each fit variable.
static Float_t mTowerWidthXY[2]
glass width X, Y in cm
static void minimizationFunction2Photon(Int_t &nparam, Double_t *grad, Double_t &fval, Double_t *param, Int_t iflag)
const StFmsHit * hit() const
Definition: StFmsTower.h:80
Int_t fit2PhotonCluster(const Double_t *para, const Double_t *step, const Double_t *low, const Double_t *up, PhotonList *photons)
std::vector< Float_t > towerWidths(Int_t detectorId) const
std::list< StFmsFittedPhoton > PhotonList
Int_t row() const
Definition: StFmsTower.h:84
Double_t mTowerWidth
width of one lead glass module
static void minimizationFunctionNPhoton(Int_t &npar, Double_t *grad, Double_t &fval, Double_t *par, Int_t iflag)
static StFmsTowerCluster::Towers * mTowers
List of towers to fit.