Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DBCALCluster.cc
Go to the documentation of this file.
1 /*
2  * DBCALCluster.cc
3  *
4  * Created by Matthew Shepherd on 3/13/11.
5  *
6  */
7 
8 #include "BCAL/DBCALCluster.h"
9 #include "BCAL/DBCALPoint.h"
10 #include "units.h"
11 
12 
13 #include <math.h>
14 #include <TMath.h>
15 
16 DBCALCluster::DBCALCluster( const DBCALPoint* point, double z_target_center, double q, const DBCALGeometry *locGeom )
17  : m_points ( 0 ), m_hit_E_unattenuated_sum(0.0), m_point_reatten_E_sum(0.0), m_z_target_center(z_target_center), new_point_q(q), m_BCALGeom(locGeom) {
18 
19  m_points.push_back( point );
21 }
22 
23 DBCALCluster::DBCALCluster(double z_target_center, const DBCALGeometry *locGeom) : m_z_target_center(z_target_center), m_BCALGeom(locGeom) {
24  clear(); //initialize all values to zero
25 }
26 
27 float
29 
30  float path = m_BCALGeom->GetBCAL_inner_rad() / sin( m_theta );
31 
32  return m_t - ( path / ( 30 * k_cm / k_nsec ) );
33 }
34 
35 void
36 DBCALCluster::addPoint( const DBCALPoint* point, int q ){
37 
38  // offset phi of the point by +- 2TMath::Pi() to match the cluster
39  if( phi() > point->phi() ){
40 
41  if( fabs( phi() - point->phi() - 2*TMath::Pi() ) < TMath::Pi() ) point->add2Pi();
42  }
43  else{
44 
45  if( fabs( point->phi() - phi() - 2*TMath::Pi() ) < TMath::Pi() ) point->sub2Pi();
46  }
47 
48  m_points.push_back( point );
49  if( q!=2 ) new_point_q = q;
50  else new_point_q = 0;
51 
53 }
54 
55 void
57 
58 if( phi() > point->phi() ){
59 
60  if( fabs( phi() - point->phi() - 2*TMath::Pi() ) < TMath::Pi() ) point->add2Pi();
61  }
62  else{
63 
64  if( fabs( point->phi() - phi() - 2*TMath::Pi() ) < TMath::Pi() ) point->sub2Pi();
65  }
66 
67  if(find(m_points.begin(),m_points.end(),point) != m_points.end()) m_points.erase( find(m_points.begin(),m_points.end(),point ));
68 
69  // We should only be removing points from clusters during the recycle_points routine, where they are also added to a different cluster.
70 
71  int n = m_points.size();
72  if (n==0) {
73  printf("E = %f \n",m_E);
74  clear(); // don't process cluster if the last point was removed
75  } else {
77  }
78 }
79 
80 void
81 DBCALCluster::addHit( const DBCALUnifiedHit* hit, double hit_E_unattenuated ){
82 
83  m_hit_E_unattenuated_sum += hit_E_unattenuated; // add the energy of all hits in a cluster
84  m_single_ended_hits.push_back(make_pair(hit,hit_E_unattenuated));
85  AddAssociatedObject( hit );
86 
87  makeFromPoints(); // call makeFromPoints so we can include hit energy in the clusterization, but don't use any of the hit positions or times to include in the cluster averaging.
88 
89 }
90 
91 void
92 DBCALCluster::mergeClust( const DBCALCluster& clust, double point_reatten_E ){
93 
94  vector< const DBCALPoint* > otherPoints = clust.points();
95 
96  for( vector< const DBCALPoint* >::const_iterator pt = otherPoints.begin();
97  pt != otherPoints.end();
98  ++pt ){
99 
100  m_point_reatten_E_sum += point_reatten_E;
101  // offset phi of the point by +- 2TMath::Pi() to match the cluster if needed
102  if( phi() > (**pt).phi() ){
103 
104  if( fabs( phi() - (**pt).phi() - 2*TMath::Pi() ) < TMath::Pi() ) (**pt).add2Pi();
105  }
106  else{
107 
108  if( fabs( (**pt).phi() - phi() - 2*TMath::Pi() ) < TMath::Pi() ) (**pt).sub2Pi();
109  }
110 
111  m_points.push_back( *pt );
112  }
113 
114  vector<pair<const DBCALUnifiedHit*,double> > otherHits = clust.hits();
115 
116  for( vector<pair<const DBCALUnifiedHit*,double> >::const_iterator hit = otherHits.begin();
117  hit != otherHits.end();
118  ++hit ){
119 
120  m_hit_E_unattenuated_sum += hit->second; //add the unattenuated energy
121  m_single_ended_hits.push_back( *hit );
122  AddAssociatedObject( hit->first );
123  }
124 
125  makeFromPoints();
126 }
127 
128 void
130 
131  clear();
132 
133  //In this function we take a weighted average of the phis/thetas/etc
134  //of the individual DBCALPoint's to get the phi/theta/etc of the cluster. The
135  //average of phi is weighted by the energy of the hit, while the other
136  //quantities are weighted by energy squared. This sort of makes sense because
137  //the error of the phi measurement is independent of the energy of the hit,
138  //so it is only weighted because higher energy hits make up "more" of the
139  //cluster. In the case of theta/timing measurements, the error decreases with
140  //hit energy, so it makes sense to weight these with an extra factor of E, at
141  //least to some low level of rigor. In any case, the weighting scheme below
142  //produces far better angular resolutions for clusters than other
143  //weightings tested.
144 
145  //Also, don't include hits from the 4th layer in the averages.
146  //Three reasons for doing this:
147  //1) Averaging the quantities theta, rho, and phi (rather than z,r,phi) is
148  //based on the assumption that the shower develops in a linear fashion inside
149  //the BCAL. This assumption breaks down
150  //deep in the BCAL (see GlueX doc 2229 slides 21-22).
151  //(this also applies to layer 3, so at some point, we may want to
152  //consider if we want treat layer 3 differently as well)
153  //2) The errors in the outer layers for measurements of t and z are
154  //relatively large due to the lack
155  //of TDC readout so we don't gain much by including them.
156  //3) Contamination by noise. (Noise is greatest in the 4th layer)
157  //These outer layer hits will of course still contribute to the energy sum.
158  //It can happen that a cluster is made up entirely of fourth layer hits.
159  //In this case, we must use all hits in the average.
160 
161  //Add single-ended hit energies to the cluster energy, but don't use the single-ended hits
162  //to calculate the cluster centroid or time.
163 
164  int n = m_points.size();
165  int min_z = -100;
166  int max_z = 500; // z limits to be included in the position and time averaging
167  if (n==0) printf("0 point cluster\n");
168  int n4 = 0; //number of 4th layer points in the cluster
169  for( vector< const DBCALPoint* >::const_iterator pt = m_points.begin();
170  pt != m_points.end();
171  ++pt ){
172  if ((**pt).layer() == 4) n4++;
173  }
174 
175  bool average_layer4;
176  int n_avg; //number of points involved in the average
177  if (n == n4) { //if all points are in the 4th layer
178  average_layer4 = true; //include 4th layer in average
179  n_avg = n4;
180  } else {
181  average_layer4 = false;
182  n_avg = n - n4; //all points except 4th layer involved in average
183  }
184 
185  double sum_wt1 = 0;
186  double sum_wt1_sq = 0;
187  double sum_wt2 = 0;
188  double sum_wt2_sq = 0;
189  //to do an average of phi correctly for cases with angles near 0, we need to average cos(phi) and sin(phi) instead of phi itself
190  double sum_sin_phi=0;
191  double sum_cos_phi=0;
192  charge = 0;
193  float t_mean = 0.;
194 
195  for( vector< const DBCALPoint* >::const_iterator pt = m_points.begin();
196  pt != m_points.end();
197  ++pt ){
198  double E = (**pt).E();
199  double z = (**pt).z();
200 
201  if(m_point_reatten_E_sum == 0) m_E_points += E;
202  else if (z > min_z && z < max_z ) m_E_points += E; // if a point was reconstructed outside of the BCAL we want to add it's energy but not let it contribute to the time or position recon.
203  m_E = m_E_points + m_hit_E_unattenuated_sum + m_point_reatten_E_sum ; // add the energy sum from points to the energy sum from single ended hits
204  if( E == m_E_points || ( (**pt).layer()==1 && charge == 0 ) ) charge = new_point_q;
205 
206  if ((**pt).layer() == 1) m_E_preshower += E;
207  if ((**pt).layer() == 2) m_E_L2 += E;
208  if ((**pt).layer() == 3) m_E_L3 += E;
209  if ((**pt).layer() == 4) m_E_L4 += E;
210 
211  double wt1, wt2;
212  if ( ( m_point_reatten_E_sum == 0 && ( (**pt).layer() != 4 || average_layer4 ) ) ) {
213  wt1 = E;
214  wt2 = E*E;
215  } else if ( ( (**pt).layer() != 4 || average_layer4 ) && z > min_z && z < max_z ) {
216  wt1 = E;
217  wt2 = E*E;
218  } else {
219  wt1 = 0;
220  wt2 = 0;
221  }
222 
223  sum_wt1 += wt1;
224  sum_wt1_sq += wt1*wt1;
225  sum_wt2 += wt2;
226  sum_wt2_sq += wt2*wt2;
227 
228  m_t += (**pt).tInnerRadius() * wt2;
229  m_sig_t += (**pt).tInnerRadius() * (**pt).tInnerRadius() * wt2;
230  t_mean += (**pt).t();
231 
232  m_theta += (**pt).theta() * wt2;
233  m_sig_theta += (**pt).theta() * (**pt).theta() * wt2;
234 
235  sum_sin_phi += sin((**pt).phi()) * wt1;
236  sum_cos_phi += cos((**pt).phi()) * wt1;
237 
238  m_rho += (**pt).rho() * wt2;
239  m_sig_rho += (**pt).rho() * (**pt).rho() * wt2;
240 
241  }
242 
243  // now adjust the standard deviations and averages
244  // the variance of the mean of a weighted distribution is s^2/n_eff, where s^2 is the variance of the sample and n_eff is as calculated below
245 
246  //double n_eff1 = sum_wt1*sum_wt1/sum_wt1_sq;
247  double n_eff2 = sum_wt2*sum_wt2/sum_wt2_sq;
248 
249  m_t /= sum_wt2;
250  m_sig_t /= sum_wt2;
251  m_sig_t -= ( m_t * m_t );
252  m_sig_t = sqrt( m_sig_t );
253  m_sig_t /= sqrt(n_eff2);
254 
255  t_mean /= n;
256 
257  m_theta /= sum_wt2;
258  /*m_sig_theta /= sum_wt2;
259  m_sig_theta -= ( m_theta * m_theta );
260  m_sig_theta = sqrt( fabs( m_sig_theta ) );
261  m_sig_theta /= sqrt(n_eff2);*/
262 
263  // The method below for determining sig_theta works better than the one
264  // above. parameters of sigma_z are determined using errors when reconstructing MC data.
265  // Using m_E_points because the cluster z position only depends on the point z positions
266  // and point energies.
267  double sigma_z = sqrt(1.394*1.394/m_E_points + 0.859*0.859);
269 
270  m_phi = atan2(sum_sin_phi,sum_cos_phi);
271  if( m_phi < 0 ) m_phi += 2*TMath::Pi();
272  // calculate the RMS of phi
273  m_sig_phi=0;
274 
275  float t_quad_sum = 0.;
276 
277  for( vector< const DBCALPoint* >::const_iterator pt = m_points.begin();
278  pt != m_points.end();
279  ++pt ){
280 
281  double E = (**pt).E();
282 
283  double wt1;
284  if ((**pt).layer() != 4) {
285  wt1 = E;
286  } else {
287  wt1 = 0;
288  }
289 
290  double deltaPhi = (**pt).phi() - m_phi;
291  double deltaPhiAlt = ( (**pt).phi() > m_phi ?
292  (**pt).phi() - m_phi - 2*TMath::Pi() :
293  m_phi - (**pt).phi() - 2*TMath::Pi() );
294  deltaPhi = min( fabs( deltaPhi ), fabs( deltaPhiAlt ) );
295  m_sig_phi += deltaPhi * deltaPhi * wt1;
296 
297  float t = (**pt).t();
298  t_quad_sum += (t-t_mean)*(t-t_mean);
299 
300  }
301  m_t_rms = sqrt(t_quad_sum/(n+1.));
302  m_sig_phi /= sum_wt1;
303  m_sig_phi = sqrt( fabs(m_sig_phi) );
304  //this should be division, by sqrt(n_eff1), but this works better
305  m_sig_phi /= sqrt(n_avg);
306 
307  m_rho /= sum_wt2;
308  m_sig_rho /= sum_wt2;
309  m_sig_rho -= ( m_rho * m_rho );
310  m_sig_rho = sqrt( fabs( m_sig_rho ) );
311  m_sig_rho /= sqrt(n_eff2);
312 
313  //Since the z-positions of the DBCALPoint's are not constrained to be
314  //physical (be inside the BCAL), we can end up with clusters outside of the
315  //BCAL.
316  //Also, in extreme cases, the averaging procedure itself can lead to positions
317  //outside the BCAL.
318  //So at this point, convert our cluster position to cylindrical coordinates,
319  //constrain r and z to be inside the BCAL and then convert back to
320  //spherical coordinates.
321  double z = m_rho*cos(m_theta) + m_z_target_center;
322  double r = m_rho*sin(m_theta);
323 
324  double bcal_down = m_BCALGeom->GetBCAL_center() + m_BCALGeom->GetBCAL_length()/2.0;
325  double bcal_up = m_BCALGeom->GetBCAL_center() - m_BCALGeom->GetBCAL_length()/2.0;
326  if (z > bcal_down) z = bcal_down;
327  if (z < bcal_up) z = bcal_up;
328 
329  double r_min = m_BCALGeom->r(m_BCALGeom->cellId(1,1,1)); //This is the center of the first layer of the BCAL. This is the minimum value of r that a DBCALPoint will report.
330  double r_max = m_BCALGeom->r(m_BCALGeom->cellId(1,4,1)); //Maximum r that a DBCALPoint will report
331  if (r > r_max) r = r_max;
332  if (r < r_min) r = r_min;
333 
334  m_theta = atan2(r, (z-m_z_target_center));
335  m_rho = sqrt(r*r + (z-m_z_target_center)*(z-m_z_target_center));
336 
337  // if we only have one point, then set sizes based on the size
338  // of the point
339 
340  if( m_points.size() == 1 ){
341 
342  m_sig_theta = m_points[0]->sigTheta();
343  m_sig_phi = m_points[0]->sigPhi();
344  m_sig_rho = m_points[0]->sigRho();
345  }
346 
347  // it is also possible to have sigPhi be zero when all points
348  // lie in the same radial "tower" and sigTheta can be zero
349  // if two points are at the end of the module (same z) in the
350  // same layer in these cases set sigmas to the characteristic
351  // size of the cell
352  // (this condition can also occur if we have one or more 4th layer points
353  // in addition to a single inner layer hit
354 
355  //need to think about what to do with these sqrt(n)'s
356  //also should add sig_phi and sig_theta here
357  if( m_sig_phi < 1E-6 ) m_sig_phi = m_points.at(0)->sigPhi()/sqrt(n_avg);
358  if( m_sig_theta < 1E-6 ) m_sig_theta = m_points.at(0)->sigPhi()/sqrt(n_avg);
359 
360  // correct phi of the cluster if we've drifted outside of 0 - 2TMath::Pi()
361  if( m_phi > 2*TMath::Pi() ) m_phi -= 2*TMath::Pi();
362  if( m_phi < 0 ) m_phi += 2*TMath::Pi();
363 }
364 
365 void
366 DBCALCluster::toStrings( vector< pair < string, string > > &items) const {
367 
368  AddString(items, "r", "%5.2f", m_rho * sin( m_theta ) );
369  AddString(items, "phi", "%5.2f", m_phi );
370 // AddString(items, "dphi", "%5.2f", m_sig_phi );
371  AddString(items, "z", "%5.2f", m_rho * cos( m_theta ) + m_z_target_center );
372  AddString(items, "theta", "%5.2f", m_theta);
373 // AddString(items, "dtheta", "%5.2f", m_sig_theta);
374  AddString(items, "t", "%5.2f", m_t );
375  AddString(items, "E", "%5.2f", m_E );
376  AddString(items, "E_preshower", "%5.2f", m_E_preshower );
377  AddString(items, "E_L2", "%5.2f", m_E_L2 );
378  AddString(items, "E_L3", "%5.2f", m_E_L3 );
379  AddString(items, "E_L4", "%5.2f", m_E_L4 );
380  AddString(items, "N_cell", "%i", m_points.size() );
381  AddString(items, "charge", "%i", charge );
382  AddString(items, "t_rms", "%5.2f", m_t_rms );
383 
384 }
385 
386 
387 void
389 
390  m_E = 0;
391  m_E_points = 0;
392  m_E_preshower = 0;
393  m_E_L2 = 0;
394  m_E_L3 = 0;
395  m_E_L4 = 0;
396  m_t = 0;
397  m_sig_t = 0;
398  m_t_rms = 0;
399 
400  m_theta = 0;
401  m_sig_theta = 0;
402 
403  m_phi = 0;
404  m_sig_phi = 0;
405 
406  m_rho = 0;
407  m_sig_rho = 0;
408 
409 }
410 
vector< const DBCALPoint * > m_points
Definition: DBCALCluster.h:84
float t0() const
Definition: DBCALCluster.cc:28
void toStrings(vector< pair< string, string > > &items) const
void mergeClust(const DBCALCluster &clust, double point_reatten_E)
Definition: DBCALCluster.cc:92
const DBCALGeometry * m_BCALGeom
Definition: DBCALCluster.h:111
void sub2Pi() const
Definition: DBCALPoint.cc:187
float phi() const
Definition: DBCALPoint.h:56
float t() const
Definition: DBCALCluster.h:49
float GetBCAL_length() const
const double k_cm
Definition: units.h:14
void addHit(const DBCALUnifiedHit *hit, double hit_E_unattenuated)
Definition: DBCALCluster.cc:81
vector< pair< const DBCALUnifiedHit *, double > > m_single_ended_hits
Definition: DBCALCluster.h:86
float m_point_reatten_E_sum
Definition: DBCALCluster.h:89
vector< pair< const DBCALUnifiedHit *, double > > hits() const
Definition: DBCALCluster.h:35
float GetBCAL_inner_rad() const
float m_z_target_center
Definition: DBCALCluster.h:108
float m_sig_theta
Definition: DBCALCluster.h:104
float r(int fADC_cellId) const
vector< const DBCALPoint * > points() const
Definition: DBCALCluster.h:31
void addPoint(const DBCALPoint *point, int q)
Definition: DBCALCluster.cc:36
double sqrt(double)
float m_E_points
Definition: DBCALCluster.h:90
double sin(double)
float phi() const
Definition: DBCALCluster.h:65
void removePoint(const DBCALPoint *point)
Definition: DBCALCluster.cc:56
const double k_nsec
Definition: units.h:67
float GetBCAL_center() const
void add2Pi() const
Definition: DBCALPoint.cc:181
void makeFromPoints()
DBCALCluster(double z_target_center, const DBCALGeometry *locGeom)
Definition: DBCALCluster.cc:23
int cellId(int module, int layer, int sector) const
these functions are about encoding/decoding module/layer/sector info in a cellId
printf("string=%s", string)
float m_hit_E_unattenuated_sum
Definition: DBCALCluster.h:88
float m_E_preshower
Definition: DBCALCluster.h:92
float E() const
Definition: DBCALCluster.h:41