StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StFmsPointMaker.cxx
Go to the documentation of this file.
1 // $Id: StFmsPointMaker.cxx,v 1.14 2019/06/26 16:49:43 akio Exp $
2 //
3 // $Log: StFmsPointMaker.cxx,v $
4 // Revision 1.14 2019/06/26 16:49:43 akio
5 // shower shape scaling for all shapes
6 //
7 // Revision 1.13 2018/03/02 20:26:44 akio
8 // Big update from Zhanwen Zhu with new shower shape and six z slices
9 //
10 // Revision 1.12 2018/01/04 17:35:44 smirnovd
11 // [Cosmetic] Remove StRoot/ from include path
12 //
13 // $STAR/StRoot is already in the default path search
14 //
15 // Revision 1.11 2016/11/22 18:24:34 akio
16 // Using StFmsDbMaker::getLorentzVector for correct momentum calcuration based on beamline angles/offsets
17 //
18 // Revision 1.10 2016/06/07 15:51:43 akio
19 // Making code better based on Coverity reports
20 //
21 // Revision 1.9 2015/11/05 17:53:09 akio
22 // Adding setScaleShowerShape() option for scaling up shower shape function for large cell
23 //
24 // Revision 1.8 2015/11/04 21:57:43 akio
25 // fixing overwrting detectorId for some StFmsPoint near large/small gap when
26 // top cell in the cluster and the photon are in different detector
27 //
28 // Revision 1.7 2015/11/02 22:40:04 akio
29 // adding option for new cluster categorization
30 //
31 // Revision 1.6 2015/10/30 21:23:04 akio
32 // *** empty log message ***
33 //
34 // Revision 1.5 2015/10/29 21:17:41 akio
35 // Fix small scale differebce for small cells when converting coordinates while mMergeSmallToLarge is on
36 // Cleaning up debug prints
37 //
38 // Revision 1.4 2015/10/21 15:49:12 akio
39 // Adding 3 options to control how reconstruction works:
40 // setGlobalRefit(int v=1)
41 // setMergeSmallToLarge(int v=1)
42 // setTry1PhotonFit(int v=1)
43 //
44 // Revision 1.3 2015/09/18 18:46:47 akio
45 // Move energy sum check for killing LED tail event to whole FMS, not each module
46 // Also make it not dependent on beam energy, so that it runs on simulation as well.
47 //
48 // Revision 1.2 2015/09/02 14:52:15 akio
49 // Adding readMuDst() to give options when reading back from mudst
50 //
58 #include "StFmsPointMaker.h"
59 
60 #include "StLorentzVectorF.hh"
61 #include <TProcessID.h>
62 
63 
64 #include "StMuDSTMaker/COMMON/StMuTypes.hh"
65 #include "StMuDSTMaker/COMMON/StMuDst.h"
66 #include "StMuDSTMaker/COMMON/StMuEvent.h"
67 
68 #include "StMessMgr.h"
69 #include "StEvent.h"
70 #include "StEnumerations.h"
71 #include "StFmsCluster.h"
72 #include "StFmsCollection.h"
73 #include "StFmsHit.h"
74 #include "StFmsPoint.h"
75 #include "StRunInfo.h"
76 #include "StFmsDbMaker/StFmsDbMaker.h"
77 
80 #include "StFmsUtil/StFmsTower.h"
82 #include "StFmsUtil/StFmsConstant.h"
83 
84 namespace {
85  // Calculate a 4 momentum from a direction/momentum vector and energy
86  // assuming zero mass i.e. E = p
87  StLorentzVectorF compute4Momentum(const StThreeVectorF& xyz, Float_t energy) {
88  StThreeVectorF mom3 = xyz.unit() * energy; // Momentum vector with m = 0
89  return StLorentzVectorF(mom3, energy);
90  }
91 } // unnamed namespace
92 
94  : StMaker(name) {}
95 
97 
98 Int_t StFmsPointMaker::InitRun(Int_t runNumber) {
99  // Ensure we can access database information
100  LOG_DEBUG << "StFmsPointMaker initializing run" << endm;
101  mFmsDbMaker = static_cast<StFmsDbMaker*>(GetMaker("fmsDb"));
102  if (!mFmsDbMaker) {
103  LOG_ERROR << "StFmsPointMaker initializing failed due to no StFmsDbMaker" << endm;
104  return kStErr;
105  }
106  /*
107  // Set up geometry, which stays constant for each run
108  if (!mGeometry.initialize(mFmsDbMaker)) {
109  // Return an error if geometry initialization fails
110  return kStErr;
111  } // if
112  */
113  return StMaker::InitRun(runNumber);
114 }
115 
117  // Cache the current count of referenced objects, as discussed here
118  // http://root.cern.ch/root/htmldoc/TRef.html
123  LOG_DEBUG << "StFmsPointMaker making" << endm;
124  if(mReadMuDst) return readMuDst();
125 
126  vertexz = 0 ;
127  if(mVertexZ==1){
128  muDst = (StMuDst*)GetInputDS("MuDst");
129  if(muDst) {
130  // get vertex Z from BBCTime
131  unsigned short bbcTimeBin = muDst->event()->bbcTriggerDetector().onlineTimeDifference();
132  if (bbcTimeBin!=0) vertexz = 633.544 - 0.158*bbcTimeBin;
133  }
134  }
135 
136  mObjectCount = TProcessID::GetObjectCount();
137  if (!populateTowerLists()) { //this also assigns mFmsCollection
138  return kStOK; //return ok even if energy sum exceed max
139  //LOG_ERROR << "StFmsPointMaker::Make() - failed to initialise tower " <<
140  // "lists for the event" << endm;
141  //return kStErr;
142  } // if
143  clusterEvent();
144  return StMaker::Make();
145 }
146 
147 void StFmsPointMaker::Clear(Option_t* option) {
148  mTowers.clear();
149  // Reset the count of referenced objects to the value before the previous
150  // call to Make(), in order prevent ever-growing table of objects
151  TProcessID::SetObjectCount(mObjectCount);
152  StMaker::Clear(option);
153 }
154 
155 StFmsCollection* StFmsPointMaker::getFmsCollection() {
156  StEvent* event = static_cast<StEvent*>(GetInputDS("StEvent"));
157  StFmsCollection* fms = nullptr;
158  if (event) {
159  fms = event->fmsCollection();
160  } // if
161  if (!fms) {
162  LOG_ERROR << "StFmsPointMaker did not find "
163  << "an StFmsCollection in StEvent" << endm;
164  } // if
165  return fms;
166 }
167 
168 int StFmsPointMaker::clusterEvent() {
169  if (!mFmsCollection) {
170  return kStErr;
171  } // if
172  for (auto i = mTowers.begin(); i != mTowers.end(); ++i) {
173  /* Removing LED tail was moved to populateTowerList()
174  if (!validateTowerEnergySum(i->second)) {
175  continue; // To remove LED trails
176  } // if
177  */
178  clusterDetector(&i->second, i->first);
179  } // for
180  mFmsCollection->setMergeSmallToLarge(mMergeSmallToLarge);
181  mFmsCollection->setGlobalRefit(mGlobalRefit);
182  mFmsCollection->setTry1PhotonFit(mTry1PhotonFitWhen2PhotonFitFailed);
183  mFmsCollection->setNewClusterCategorization(mCategorizationAlgo);
184  mFmsCollection->setScaleShowerShape(1);
185  mFmsCollection->setScaleShowerShape(mScaleShowerShapeLarge,mScaleShowerShapeSmall);
186  mFmsCollection->sortPointsByEnergy();
187  LOG_INFO << Form("Found %d Clusters and %d Points",mFmsCollection->numberOfClusters(),mFmsCollection->numberOfPoints()) << endm;
188  return kStOk;
189 }
190 
191 /* Perform photon reconstruction on a single sub-detector */
192 int StFmsPointMaker::clusterDetector(TowerList* towers, const int detectorId) {
193  // FMSCluster::StFmsEventClusterer clustering(&mGeometry,detectorId);
194  FMSCluster::StFmsEventClusterer clustering(mFmsDbMaker,detectorId,mGlobalRefit,mMergeSmallToLarge,
195  mTry1PhotonFitWhen2PhotonFitFailed,mCategorizationAlgo,
196  mScaleShowerShapeLarge,mScaleShowerShapeSmall,
197  mShowerShapeWithAngle,vertexz);
198  // Perform tower clustering, skip this subdetector if an error occurs
199  if (!clustering.cluster(towers)) { // Cluster tower list
200  //LOG_INFO << Form("clusterDetector found no cluster for det=%d ",detectorId)<<endm;
201  return kStOk; // this happens if detector just had too low energy
202  } // if
203  // Saved cluster info into StFmsCluster
204  auto& clusters = clustering.clusters();
205  for (auto cluster = clusters.begin(); cluster != clusters.end(); ++cluster) {
206  processTowerCluster(cluster->get(), detectorId);
207  } // for
208  LOG_DEBUG << Form("Found %d clusters for det=%d",clusters.size(),detectorId)<<endm;
209  return kStOk;
210 }
211 
212 /* Moving this to populateTowerLists()
213 bool StFmsPointMaker::validateTowerEnergySum(const TowerList& towers) const {
214  // remove acceing centerOfMassEnergy in StEvent, which can be
215  // garbage for MC. BTW, shouldn't this be 1/2 of 510/200GeV?
216  // Attempt to get center-of-mass energy from StRunInfo.
217  // If it can't be accessed assume 500 GeV running.
218  double centerOfMassEnergy(500.);
219  const StEvent* event = static_cast<const StEvent*>(GetInputDS("StEvent"));
220  if (event) {
221  if (event->runInfo()) {
222  centerOfMassEnergy = event->runInfo()->centerOfMassEnergy();
223  } // if
224  } // if
225 
226  // Sum tower energies and test validity of the sum
227  double Esum = 0.f;
228  typedef TowerList::const_iterator TowerIter;
229  for (TowerIter i = towers.begin(); i != towers.end(); ++i) {
230  Esum += i->hit()->energy();
231  } // for
232  LOG_DEBUG << Form("Esum=%f Max=%f",Esum,mMaxEnergySum) <<endm;
233  return Esum >= 0.f && Esum <= mMaxEnergySum;
234 }
235 */
236 
237 bool StFmsPointMaker::processTowerCluster(
238  FMSCluster::StFmsTowerCluster* towerCluster,
239  const int detectorId) {
240  // Update the StFmsCluster object we want to store in StEvent with information
241  // not automatically propagated via StFmsTowerCluster
242  StFmsCluster* cluster = towerCluster->cluster();
243  // Skip clusters that don't have physically sensible coordinates
244  if (!(cluster->x() > 0. && cluster->y() > 0.)) {
245  LOG_INFO << "Found cluster x or y is zero, not processing this cluster" << endm;
246  return false;
247  } // if
248  int det=detectorId;
249  float x=cluster->x();
250  float y=cluster->y();
251  if(mMergeSmallToLarge>0){
252  if(x<8.0 && y>9.0 && y<25.0){ // Central hole, those are small cell merged to large
253  det=detectorId+2; //put back to small cell coordinate
254  cluster->setX(x*1.5);
255  cluster->setY((y-9.0)*1.5);
256  }
257  }
258  cluster->setDetectorId(det);
259  // Cluster id is id of the 1st photon, not necessarily the highest-E photon
260  //cluster->setId(CLUSTER_BASE + CLUSTER_ID_FACTOR_DET * det + mFmsCollection->numberOfPoints());
261  cluster->setId(200*(det-kFmsNorthLargeDetId) + mFmsCollection->numberOfPoints());
262  // Cluster locations are in column-row grid coordinates so convert to cm and get STAR xyz
263  StThreeVectorF xyz = mFmsDbMaker->getStarXYZfromColumnRow(det,cluster->x(),cluster->y());
264  // putting z position where angled shower shape uses as z reference
265  if( mShowerShapeWithAngle>0 ) xyz.setZ (735.45);
266  //cluster->setFourMomentum(compute4Momentum(xyz, cluster->energy()));
267  cluster->setFourMomentum(mFmsDbMaker->getLorentzVector(xyz,cluster->energy()));
268 
269  // Save photons reconstructed from this cluster
270  for (UInt_t np = 0; np < towerCluster->photons().size(); np++) {
271  StFmsPoint* point = makeFmsPoint(towerCluster->photons()[np], detectorId);
272  // point->setId(CLUSTER_BASE + CLUSTER_ID_FACTOR_DET * det + mFmsCollection->numberOfPoints());
273  point->setId(200*(det-kFmsNorthLargeDetId) + mFmsCollection->numberOfPoints());
274  point->setParentClusterId(cluster->id());
275  point->setNParentClusterPhotons(towerCluster->photons().size());
276  point->setCluster(cluster);
277  // Add it to both the StFmsCollection and StFmsCluster
278  // StFmsCollection owns the pointer, the cluster merely references it
279  mFmsCollection->points().push_back(point);
280  cluster->points().push_back(point);
281  } // for
282  // Save the tower hit info.
283  auto& towers = towerCluster->towers();
284  for (auto i = towers.begin(); i != towers.end(); ++i) {
285  if ((*i)->hit()->adc() >= 1) { // Min ADC = 1
286  cluster->hits().push_back((*i)->hit());
287  } // if
288  } // for
289  // Release StFmsCluster held by towerCluster to pass ownership to
290  // StFmsCollection (and hence StEvent).
291  mFmsCollection->addCluster(towerCluster->release());
292  return true;
293 }
294 
295 StFmsPoint* StFmsPointMaker::makeFmsPoint(
296  const FMSCluster::StFmsFittedPhoton& photon, const int detectorId) {
297  StFmsPoint* point = new StFmsPoint;
298  float x=photon.x; //photon xy is in detector local coordinate in [cm]
299  float y=photon.y;
300  int det=detectorId;
301  float lwx=mFmsDbMaker->getXWidth(kFmsNorthLargeDetId);//take large cell width since all merged to large cell
302  float lwy=mFmsDbMaker->getYWidth(kFmsNorthLargeDetId);
303  float wx=mFmsDbMaker->getXWidth(kFmsNorthSmallDetId);
304  float wy=mFmsDbMaker->getYWidth(kFmsNorthSmallDetId);
305  if(mMergeSmallToLarge>0){
306  if(x<8.0*lwx && y>9.0*lwy && y<25.0*lwy){ // Central hole, those are small cell merged to large
307  x = x/lwx*1.5*wx;
308  y = (y/lwy - 9.0)*1.5*wy;
309  det+=2;
310  }
311  }
312  point->setEnergy(photon.energy);
313  point->setDetectorId(det);
314  point->setX(x); //Akio propose to keep fitted local X here
315  point->setY(y); //Akio propose to keep fitted local Y here
316  // Calculate photon 4 momentum
317  // StFmsFittedPhoton position is in detector-local (x, y) [cm] coordinates
318  // Convert to global STAR coordinates for StFmsPoint
319  StThreeVectorF xyz = mFmsDbMaker->getStarXYZ(det,x,y);
320  // putting z position where angled shower shape uses as z reference
321  if( mShowerShapeWithAngle>0) xyz.setZ(735.45);
322  point->setXYZ(xyz); //This is in STAR global coordinate
323  point->setFourMomentum(mFmsDbMaker->getLorentzVector(xyz,point->energy()));
324  return point;
325 }
326 
327 bool StFmsPointMaker::populateTowerLists() {
328  mFmsCollection = getFmsCollection();
329  if (!mFmsCollection) {
330  LOG_ERROR << "mFmsCollection is null" << endm;
331  return false;
332  } // if
333  auto& hits = mFmsCollection->hits();
334  LOG_DEBUG << "Found nhits = " << hits.size() << endm;
335  float sumE[5]={0.0,0.0,0.0,0.0,0.0};
336  int n=0;
337  for (auto i = hits.begin(); i != hits.end(); ++i) {
338  StFmsHit* hit = *i;
339  int detector = hit->detectorId();
340  const int row = mFmsDbMaker->getRowNumber(detector, hit->channel());
341  const int column = mFmsDbMaker->getColumnNumber(detector, hit->channel());
342  if (!isValidChannel(detector, row, column)) {
343  continue;
344  } // if
345  if(mMergeSmallToLarge>0){
346  if(detector==kFmsNorthSmallDetId) detector=kFmsNorthLargeDetId;
347  if(detector==kFmsSouthSmallDetId) detector=kFmsSouthLargeDetId;
348  }
349  if (hit->adc() > 0) {
350  sumE[0]+=hit->energy();
351  sumE[detector-kFmsNorthLargeDetId+1]+=hit->energy();
352  // Insert a tower list for this detector ID if there isn't one already
353  // This method is faster than using find() followed by insert()
354  // http://stackoverflow.com/questions/97050/stdmap-insert-or-stdmap-find
355  auto low = mTowers.lower_bound(detector);
356  if (low == mTowers.end() || mTowers.key_comp()(detector, low->first)) {
357  mTowers.insert(TowerMap::value_type(detector, TowerList()));
358  } // if
359  FMSCluster::StFmsTower tower(hit);
360  // Ensure tower information is valid before adding
361  if (tower.initialize(mFmsDbMaker)) {
362  mTowers[detector].push_back(tower);
363  } // if
364  n++;
365  } // if
366  } // for
367  LOG_INFO << Form("NHit=%d NValidHit=%d Esum=%f (%f %f %f %f) Max=%f",hits.size(),n,sumE[0],sumE[1],sumE[2],sumE[3],sumE[4],mMaxEnergySum) << endm;
368  if(sumE[0]<=0.0 || sumE[0]>mMaxEnergySum) {
369  LOG_INFO << Form("Energy sum=%f exceed MaxEnergySum=%f (LED tail?) or below zero. Skipping!",sumE[0],mMaxEnergySum)<< endm;
370  return false;
371  }
372  return true;
373 }
374 
375 /* Test channel validity by detector and row, column in the range [1, N] */
376 /* the constants are defined in StFmsUtil/StFmsConstant.h*/
377 bool StFmsPointMaker::isValidChannel(int detector, int row, int column) {
378  //printf("detector=%d row=%d column=%d LS=%d\n",detector,row,column,mFmsDbMaker->largeSmall(detector));
379  // Simplest check first, test lower bounds are valid
380  if (row < ROW_LOW_LIMIT || column < COL_LOW_LIMIT) {
381  return false;
382  } // if
383  // Omit gaps in the detector
384  switch (mFmsDbMaker->largeSmall(detector)) {
385  case 0:
386  //case FMSCluster::kFmsNorthLarge: // Deliberate fall-through
387  //case FMSCluster::kFmsSouthLarge: // Large-cell FMS sub-detector
388  if (fabs(row - CEN_ROW_LRG) < CEN_ROW_WIDTH_LRG && column < CEN_UPPER_COL_LRG) { // Central hole
389  return false;
390  } // if
391  // This cuts off a 7x7 triangle from the corners
392  if (fabs(CORNER_ROW - row) + column > CORNER_LOW_COL) {
393  return false;
394  } // if
395  break;
396  case 1:
397  //case FMSCluster::kFmsNorthSmall: // Deliberate fall-through
398  //case FMSCluster::kFmsSouthSmall: // Small-cell FMS sub-detector
399  if (fabs(row - CEN_ROW_SML) < CEN_ROW_WIDTH_SML && column < CEN_UPPER_COL_SML) { // Central hole
400  return false;
401  } // if
402  break;
403  default: // Don't currently support non-FMS sub-detectors
404  return false;
405  } // switch (largesmall)
406 
407  // Test row and column number against the numbers stored in the database for
408  // this detector. Leave this to last to avoid database calls when possible.
409  // Also serves as a double-check on detector, as the database will
410  // return -1 for both numbers in case of an invalid detector number.
411  const int nRows = mFmsDbMaker->nRow(detector);
412  if (nRows < 0 || row > nRows) {
413  return false;
414  } // if
415  const int nColumns = mFmsDbMaker->nColumn(detector);
416  if (nColumns < 0 || column > nColumns) {
417  return false;
418  } // if
419  return true;
420 }
421 
422 Int_t StFmsPointMaker::readMuDst(){
423  StEvent* event = (StEvent*)GetInputDS("StEvent");
424  if(!event){LOG_INFO<<"StFmsPointMaker::readMuDst found no StEvent"<<endm; return kStErr;}
425  StFmsCollection* fmscol = event->fmsCollection();
426  if(!fmscol){LOG_INFO<<"StFmsPointMaker::readMuDst found no FmsCollection"<<endm; return kStErr;}
427  for (unsigned i(0); i < fmscol->numberOfClusters(); ++i) {
428  StFmsCluster* c = fmscol->clusters()[i];
429  if(c){
430  StThreeVectorF xyz = mFmsDbMaker->getStarXYZfromColumnRow(c->detectorId(),c->x(),c->y());
431  //c->setFourMomentum(compute4Momentum(xyz, c->energy()));
432  c->setFourMomentum(mFmsDbMaker->getLorentzVector(xyz,c->energy()));
433  }
434  }
435  for (unsigned i(0); i < fmscol->numberOfPoints(); ++i) {
436  StFmsPoint* p = fmscol->points()[i];
437  if(p){
438  StThreeVectorF xyz = mFmsDbMaker->getStarXYZ(p->detectorId(),p->x(),p->y());
439  p->setXYZ(xyz);
440  //p->setFourMomentum(compute4Momentum(xyz, p->energy()));
441  p->setFourMomentum(mFmsDbMaker->getLorentzVector(xyz,p->energy()));
442  }
443  }
444  fmscol->sortPointsByET();
445  return kStOk;
446 }
Declaration of StFmsPointMaker, the FMS cluster/photon maker.
Float_t getXWidth(Int_t detectorId)
get the offset of the detector
virtual void Clear(Option_t *option="")
User defined functions.
Definition: StMaker.cxx:634
StThreeVectorF getStarXYZfromColumnRow(Int_t detectorId, Float_t column, Float_t row)
get the STAR frame coordinates from column/row
Int_t InitRun(Int_t runNumber)
Declaration of StFmsTower, a simple FMS tower wrapper.
double x
Fitted (relative) x-position.
StLorentzVectorF getLorentzVector(const StThreeVectorF &xyz, Float_t energy)
get the STAR frame pseudo rapidity from the vertex from local X/Y [cm]
virtual Int_t Make()
Definition: StMaker.cxx:898
Int_t largeSmall(Int_t detectorId)
north or south side
Int_t getRowNumber(Int_t detectorId, Int_t ch)
maximum number of channels
Int_t nRow(Int_t detectorId)
type of the detector
StThreeVectorF getStarXYZ(Int_t detectorId, Float_t FmsX, Float_t FmsY)
get the Y width of the cell
Int_t getColumnNumber(Int_t detectorId, Int_t ch)
get the row number for the channel
double energy
Fitted energy.
Declaration of StFmsTowerCluster, a cluster of FMS towers.
Declaration of StFmsEventClusterer, manager class for clustering.
Float_t getYWidth(Int_t detectorId)
get the X width of the cell
double y
Fitted (relative) y-position.
static StMuEvent * event()
returns pointer to current StMuEvent (class holding the event wise information, e.g. event number, run number)
Definition: StMuDst.h:320
Definition: Stypes.h:40
StFmsPointMaker(const char *name="StFmsPointMaker")
void Clear(Option_t *option="")
Definition: Stypes.h:44
Declaration of StFmsFittedPhoton, a photon fitted to an FMS cluster.
Int_t nColumn(Int_t detectorId)
number of rows
Definition: Stypes.h:41