71 #include "StFmsDbMaker/StFmsDbMaker.h"
84 #include "St_base/StMessMgr.h"
85 #include "StEvent/StFmsCluster.h"
86 #include "StEvent/StFmsHit.h"
93 #include "StFmsConstant.h"
96 namespace fms = FMSCluster;
100 typedef fms::ClusterList::iterator ClusterIter;
103 int accumulatePhotons(
int nPhotons,
104 const fms::ClusterList::value_type& cluster) {
105 return nPhotons + cluster->photons().size();
109 template<
class Iterator>
110 int sumPhotonsOverClusters(Iterator start, Iterator end) {
111 return std::accumulate(start, end, 0, accumulatePhotons);
115 template<
class Container>
116 int sumPhotonsOverClusters(
const Container& clusters) {
117 return sumPhotonsOverClusters(clusters.begin(), clusters.end());
121 struct IsBadCluster {
123 IsBadCluster(
double minEnergy,
unsigned maxTowers)
124 : energy(minEnergy), towers(maxTowers) { }
125 bool operator()(
const fms::ClusterList::value_type& cluster)
const {
126 if(cluster->cluster()->energy() <= energy){
127 LOG_DEBUG << Form(
"Removing cluster because E=%f <= %f (NTower=%d)",cluster->cluster()->energy(),energy,cluster->towers().size()) << endm;
129 if(cluster->towers().size() > towers){
130 LOG_INFO << Form(
"Removing cluster because NTower=%d > %d (E=%f)",cluster->towers().size(),towers,cluster->cluster()->energy()) << endm;
132 return cluster->cluster()->energy() <= energy ||
133 cluster->towers().size() > towers;
148 const auto& photons = cluster->
photons();
149 switch (photons.size()) {
151 photon = &(photons.front());
154 if (photons.front().energy < photons.back().energy) {
155 photon = &(photons.front());
157 photon = &(photons.back());
166 struct HasRowColumn {
168 HasRowColumn(
int d,
int r,
int c) : det(d), row(r),
column(c) { }
170 return tower->
hit()->detectorId() == det && tower->
row() == row && tower->
column() ==
column ;
180 auto found = std::find_if(cluster.
towers().begin(), cluster.
towers().end(),
181 HasRowColumn(det, row, column));
182 if (found != cluster.
towers().end()) {
193 struct OnePhotonFitParameters {
194 std::vector<double> start, steps, lower, upper;
195 OnePhotonFitParameters(
const std::vector<double>& xyWidth,
197 const double x = xyWidth.at(0);
198 const double y = xyWidth.at(1);
205 steps = {0.0, 0.1*(x+y)/2.0/w, 0.1*(x+y)/2.0/w, 0.2};
206 const std::vector<double> delta = {
210 cluster->energy() * PH1_DELTA_E
212 for (
unsigned i(0); i < start.size(); ++i) {
213 lower.push_back(start.at(i) - delta.at(i));
214 upper.push_back(start.at(i) + delta.at(i));
224 struct TwoPhotonFitParameters {
225 std::array<double, 7> start, steps, lower, upper;
226 TwoPhotonFitParameters(
const std::vector<double>& xyWidth,
228 const double x = xyWidth.at(0);
229 const double y = xyWidth.at(1);
230 const auto cluster = towerCluster->
cluster();
235 if (largesmall==0) {w1=x; w2=y;}
236 else {w1=3.822; w2=3.875;}
237 LOG_DEBUG<<
"x in FitP "<< x <<
" w1="<<w1<<endm;
239 start = std::array<double, 7>{ {
244 PH2_START_FSIGMAMAX * x * cluster->sigmaMax() / 2.0,
246 gRandom->Uniform(PH2_RAN_LOW, PH2_RAN_HIGH),
249 steps = std::array<double, 7>{ {PH2_STEP_0, PH2_STEP_1, PH2_STEP_2, PH2_STEP_3, PH2_STEP_4, PH2_STEP_5, PH2_STEP_6} };
250 const double sigmaMaxE = cluster->sigmaMax() * cluster->energy();
251 double maxTheta = cluster->sigmaMin() / cluster->sigmaMax() / PH2_MAXTHETA_F;
252 maxTheta = std::min(maxTheta, TMath::PiOver2());
253 lower = std::array<double, 7>{ {
255 start.at(1) - PH2_LOWER_XF * w1 ,
256 start.at(2) - PH2_LOWER_YF * w2,
259 std::max(0.1345*2/cluster->energy()*(735.45-vertexZ) , 0.5*w1 ),
266 start.at(4) - maxTheta,
268 start.at(6) * PH2_LOWER_6_F
270 upper = std::array<double, 7>{ {
272 start.at(1) + PH2_UPPER_XF * w1,
273 start.at(2) + PH2_UPPER_YF * w2,
275 std::min(PH2_UPPER_XMIN_F * (PH2_UPPER_XMIN_P0 - sigmaMaxE), PH2_UPPER_XMIN_LIMIT) * w1 * 5,
278 start.at(4) + maxTheta,
280 start.at(6) * PH2_UPPER_6_F
284 lower.at(3) = std::min(lower.at(3), start.at(3) * 0.8);
285 upper.at(3) = std::max(upper.at(3), start.at(3) * 3.0);
293 struct GlobalPhotonFitParameters {
294 std::vector<double> start, lower, upper;
295 GlobalPhotonFitParameters(
unsigned nPhotons,
296 ClusterIter first, ClusterIter end)
298 : start(1, nPhotons), lower(1, GL_LOWER_1),
299 upper(1, fms::StFmsClusterFitter::maxNFittedPhotons() + GL_UPPER_DELTA_MAXN) {
301 for (
auto cluster = first; cluster != end; ++cluster) {
302 const auto& photons = (*cluster)->photons();
303 for (
auto p = photons.begin(); p != photons.end(); ++p) {
304 start.push_back(p->x);
305 lower.push_back(start.back() - GL_0_DLOWER);
306 upper.push_back(start.back() + GL_0_DUPPER);
307 start.push_back(p->y);
308 lower.push_back(start.back() - GL_1_DLOWER);
309 upper.push_back(start.back() + GL_1_DUPPER);
310 start.push_back(p->energy);
311 lower.push_back(start.back() * (1 - GL_2_DLOWER));
312 upper.push_back(start.back() * (1 + GL_2_DUPPER));
319 namespace FMSCluster {
322 Int_t globalrefit, Int_t mergeSmallToLarge,
323 Int_t try1PhotonFit, Int_t categorizationAlgo,
324 Float_t scaleShowerShapeLarge , Float_t scaleShowerShapeSmall,
325 Int_t showerShapeWithAngle ,
double vertexZ)
326 : mClusterFinder(0.5), mDetectorId(detectorId), mTowers(0),
327 mFmsDbMaker(db), mGlobalRefit(globalrefit), mMergeSmallToLarge(mergeSmallToLarge),
328 mTry1PhotonFitWhen2PhotonFitFailed(try1PhotonFit), mCategorizationAlgo(categorizationAlgo),
329 mScaleShowerShapeLarge(scaleShowerShapeLarge), mScaleShowerShapeSmall(scaleShowerShapeSmall),
330 mShowerShapeWithAngle(showerShapeWithAngle), vertexz(vertexZ) { }
338 LOG_ERROR <<
"StFmsEventCusterer cannot find StFmsDbMaker !!!!!!"<<endm;
341 Float_t xw = mFmsDbMaker->
getXWidth(mDetectorId);
342 Float_t yw = mFmsDbMaker->
getYWidth(mDetectorId);
343 mTowerWidthXY.clear();
344 mTowerWidthXY.push_back(xw);
345 mTowerWidthXY.push_back(yw);
347 if (mTowers->size() > TOTAL_TOWERS) {
348 LOG_ERROR <<
"Too many towers for Fit" << endm;
352 mScaleShowerShapeLarge,mScaleShowerShapeSmall,
353 mShowerShapeWithAngle,mMergeSmallToLarge,vertexz) );
357 Int_t StFmsEventClusterer::fitEvent() {
360 if(mGlobalRefit==0)
return true;
361 if(refitClusters())
return true;
362 LOG_INFO <<
"StFmsEventClusterer::fitEvent() refitClusters failed" <<endm;
365 LOG_INFO <<
"StFmsEventClusterer::fitEvent() fitClusters failed" <<endm;
372 Int_t StFmsEventClusterer::findClusters() {
373 StFmsClusterFinder::TowerList towerList;
374 for (
auto i = mTowers->begin(); i != mTowers->end(); ++i) {
375 towerList.push_back(&(*i));
377 mClusterFinder.
findClusters(&towerList, &mClusters, mDetectorId);
380 mClusters.remove_if(IsBadCluster(BAD_MIN_E_LRG, BAD_MAX_TOW_LRG));
383 mClusters.remove_if(IsBadCluster(BAD_MIN_E_SML, BAD_MAX_TOW_SML));
389 for (
auto i = mClusters.begin(); i != mClusters.end(); ++i) {
390 (*i)->findClusterAxis(mClusterFinder.
momentEnergyCutoff(),mTowerWidthXY.at(0),mTowerWidthXY.at(1));
392 return mClusters.size();
395 Bool_t StFmsEventClusterer::fitClusters() {
400 for (
auto iter = mClusters.begin(); iter != mClusters.end(); ++iter) {
404 if(mCategorizationAlgo==0) {category = mClusterFinder.
categorise(iter->get());}
405 else {category = mClusterFinder.categorise2(iter->get());}
406 mFitter->setTowers(&(*iter)->towers());
409 fit1PhotonCluster(iter->get());
412 fit2PhotonCluster(iter);
415 category = fitAmbiguousCluster(iter);
418 LOG_ERROR <<
"The logic of cluster catagory is wrong and something "
419 <<
"impossible has happened! This a catagory-" << category <<
420 " cluster! Do not know how to fit it!" << endm;
423 if (category ==
k2PhotonCluster && (*iter)->chiSquare() > BAD_2PH_CHI2) {
424 float chi2=(*iter)->chiSquare();
425 LOG_DEBUG << Form(
"chi2=%f > BAD_2PH_CHI2=%f",chi2,BAD_2PH_CHI2) << endm;
426 if(mTry1PhotonFitWhen2PhotonFitFailed){
427 const std::vector<StFmsFittedPhoton> keep = (*iter)->photons();
428 fit1PhotonCluster(iter->get());
429 float chi1=(*iter)->chiSquare();
430 LOG_DEBUG << Form(
"Tried 1-photon fit resulted with chi2=%f", chi1)<< endm;
432 LOG_DEBUG <<
"2-photon fit was better" << endm;
433 (*iter)->photons().assign(keep.begin(), keep.end());
434 (*iter)->setChiSquare(chi2);
437 LOG_DEBUG <<
"Taking 1-photon fit" << endm;
445 Bool_t StFmsEventClusterer::refitClusters() {
448 if (mClusters.size() < 2) {
452 for (
auto i = mClusters.begin(); i != mClusters.end(); ++i) {
453 towers.insert(towers.end(), (*i)->towers().begin(), (*i)->towers().end());
455 mFitter->setTowers(&towers);
456 const int nPhotons = sumPhotonsOverClusters(mClusters);
457 fitGlobalClusters(nPhotons, mClusters.size(), mClusters.begin());
458 return nPhotons == sumPhotonsOverClusters(mClusters);
461 Double_t StFmsEventClusterer::photonEnergyInCluster(
462 const StFmsTowerCluster* cluster,
463 const StFmsFittedPhoton* photon)
const {
465 const Towers& towers = cluster->towers();
466 for (
auto tower = towers.begin(); tower != towers.end(); ++tower) {
467 energy += photonEnergyInTower(*tower, photon);
472 Double_t StFmsEventClusterer::photonEnergyInTower(
473 const StFmsTower* tower,
474 const StFmsFittedPhoton* photon)
const {
479 if (mShowerShapeWithAngle>0)
return photon->energy * mFitter->showerShapeFunction()->Eval(tower->x(),photon->x,tower->y(),photon->y);
480 if (mShowerShapeWithAngle==0)
return photon->energy * mFitter->showerShapeFunction()->Eval(tower->x()-photon->x,tower->y()-photon->y);
484 Double_t StFmsEventClusterer::fit1PhotonCluster(StFmsTowerCluster* towerCluster) {
485 double w=towerCluster->towers().front()->w();
486 OnePhotonFitParameters parameters(mTowerWidthXY, towerCluster->cluster(), w);
488 double chiSquare = mFitter->fitNPhoton(parameters.start, parameters.steps,
489 parameters.lower,parameters.upper, &photons);
490 if (photons.empty()) {
491 LOG_ERROR <<
"1-photon Minuit fit found no photons" << endm;
493 towerCluster->photons().assign(photons.begin(), photons.end());
495 const int nDegreesOfFreedom =
496 std::max(
int(towerCluster->towers().size()) - 3, 1);
497 towerCluster->setChiSquare(chiSquare / nDegreesOfFreedom);
498 towerCluster->setChiSquare1(chiSquare / nDegreesOfFreedom);
499 return towerCluster->chiSquare();
503 Double_t StFmsEventClusterer::fit2PhotonCluster(ClusterIter towerCluster) {
504 double x=towerCluster->get()->towers().front()->x();
505 double y=towerCluster->get()->towers().front()->y();
507 if(mMergeSmallToLarge>0 && x<8.0 && y>9.0 && y<25.0){
510 TwoPhotonFitParameters parameters(mTowerWidthXY, towerCluster->get(), w,vertexz);
513 mFitter->fit2Photon(parameters.start, parameters.steps,
514 parameters.lower, parameters.upper, &photons);
515 if (photons.size() == 2) {
516 (*towerCluster)->photons().assign(photons.begin(), photons.end());
518 LOG_WARN <<
"2-photon Minuit fit found " << photons.size() <<
" photons"
521 chiSquare = fitGlobalClusters(2, 1, towerCluster);
522 const int nDegreesOfFreedom = std::max(1,
523 int((*towerCluster)->towers().size() - 6));
524 (*towerCluster)->setChiSquare(chiSquare / nDegreesOfFreedom);
525 (*towerCluster)->setChiSquare2(chiSquare / nDegreesOfFreedom);
526 return (*towerCluster)->chiSquare();
530 Int_t StFmsEventClusterer::fitAmbiguousCluster(ClusterIter towerCluster) {
531 const double chiSquare1Photon = fit1PhotonCluster(towerCluster->get());
532 const StFmsFittedPhoton photon = (*towerCluster)->photons().front();
535 LOG_DEBUG <<
"fitAmbiguousCluster chi2 for 1photon fit="<<chiSquare1Photon<<endm;
536 if (chiSquare1Photon >= 5.) {
537 const double chiSquare2Photon=fit2PhotonCluster(towerCluster);
538 LOG_DEBUG <<
"fitAmbiguousCluster chi2 for 2photon fit="<<chiSquare2Photon<<endm;
539 if(chiSquare2Photon <= chiSquare1Photon ){
540 LOG_DEBUG <<
"fitAmbiguousCluster 2 photon fit is better, validate2ndPhoton"<<endm;
541 if(validate2ndPhoton(towerCluster)) {
549 (*towerCluster)->setChiSquare(chiSquare1Photon);
550 (*towerCluster)->photons().assign(1, photon);
556 Double_t StFmsEventClusterer::fitGlobalClusters(
unsigned int nPhotons,
557 const unsigned int nClusters,
559 ClusterIter end = first;
560 std::advance(end, nClusters);
561 const unsigned int totalPhotons = sumPhotonsOverClusters(first, end);
562 if (totalPhotons != nPhotons) {
563 LOG_WARN <<
"Global fit called for " << nPhotons <<
" but found " <<
564 totalPhotons <<
"... will proceed with " << totalPhotons << endm;
565 nPhotons = totalPhotons;
568 LOG_ERROR <<
"Global fit cannot fit " << nPhotons <<
" photons" << endm;
571 GlobalPhotonFitParameters parameters(nPhotons, first, end);
573 Double_t chiSquare = mFitter->fitNPhoton(parameters.start, parameters.lower,
574 parameters.upper, &photons);
575 if (photons.size() == nPhotons) {
577 auto photon = photons.begin();
578 for (ClusterIter cluster = first; cluster != end; ++
cluster) {
579 auto& ph = (*cluster)->photons();
580 for (
auto p = ph.begin(); p != ph.end(); ++p, ++photon) {
585 LOG_WARN <<
"Global Minuit fit found " << photons.size() <<
586 " photons but expected " << nPhotons << endm;
602 bool StFmsEventClusterer::validate2ndPhoton(ClusterConstIter cluster)
const {
604 const StFmsFittedPhoton* photon = findLowestEnergyPhoton(cluster->get());
605 double x=photon->x / mTowerWidthXY.at(0);
606 double y=photon->y / mTowerWidthXY.at(1);
608 int column = 1 + int(x);
609 int row = 1 + int(y);
610 if(mMergeSmallToLarge>0 && x<8.0 && y>9.0 && y<25.0){
611 column = 1 + int(x*1.5);
612 row = 1 + int((y-9.0)*1.5);
615 const StFmsTower* tower = searchClusterTowers(det, row, column, **cluster);
618 LOG_DEBUG <<
"StFmsEventClusterer::validate2ndPhoton No hit on photon" << endm;
622 if (tower->hit()->energy() < VALID_FT * photon->energy) {
623 LOG_DEBUG <<
"StFmsEventClusterer::validate2ndPhoton hit on photon too low" << endm;
628 if (tower->hit()->energy() > VALID_2ND_FT * photonEnergyInTower(tower, photon)) {
629 LOG_DEBUG <<
"StFmsEventClusterer::validate2ndPhoton photon energy too low compared to other photon" << endm;
633 const double energyInOwnCluster =
634 photonEnergyInCluster(cluster->get(), photon);
635 for (ClusterConstIter i = mClusters.begin(); i != mClusters.end(); ++i) {
637 if (photonEnergyInCluster(i->get(), photon) > VALID_E_OWN * energyInOwnCluster) {
638 LOG_DEBUG <<
"StFmsEventClusterer::validate2ndPhoton photon is at edge of another cluster" << endm;
643 LOG_DEBUG <<
"StFmsEventClusterer::validate2ndPhoton OK" << endm;
Could be 1- or 2-photon, needs to be fitted.
A cluster created by 2 photons.
Declaration of StFmsClusterFitter, shower-shape fitting routine.
Float_t getXWidth(Int_t detectorId)
get the offset of the detector
Bool_t cluster(std::vector< FMSCluster::StFmsTower > *towers)
const StFmsHit * hit() const
int categorise(StFmsTowerCluster *cluster)
Declaration of StFmsTower, a simple FMS tower wrapper.
std::list< StFmsTower * > Towers
Shorthand for tower collection.
Int_t largeSmall(Int_t detectorId)
north or south side
Declaration of StFmsTowerCluster, a cluster of FMS towers.
Declaration of StFmsEventClusterer, manager class for clustering.
int findClusters(TowerList *towers, ClusterList *clusters, int detetorId)
static int maxNFittedPhotons()
Float_t getYWidth(Int_t detectorId)
get the X width of the cell
Double_t thetaAxis() const
A cluster created by 1 photon.
double momentEnergyCutoff() const
Declaration of StFmsFittedPhoton, a photon fitted to an FMS cluster.
StFmsEventClusterer(StFmsDbMaker *db, Int_t detectorId, Int_t globalrefit, Int_t mergeSmallToLarge, Int_t try1Photon, Int_t categorizationAlgo, Float_t scaleShowerShapeLarge, Float_t scaleShowerShapeSmall, Int_t showerShapeWithAngle, double vertexz)