CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch9/src/Fireworks/Calo/src/FWECALDetailViewBuilder.cc

Go to the documentation of this file.
00001 // FIXME - needed to set fixed eta-phi limits. Without the
00002 //         visible area may change widely depending on energy
00003 //         deposition availability
00004 
00005 #include "TEveCaloData.h"
00006 #include "TEveViewer.h"
00007 #include "TEveCalo.h"
00008 #include "TAxis.h"
00009 #include "THLimitsFinder.h"
00010 #include "TLatex.h"
00011 
00012 #include "Fireworks/Core/interface/FWDetailViewBase.h"
00013 #include "Fireworks/Calo/interface/FWECALDetailViewBuilder.h"
00014 #include "Fireworks/Core/interface/FWGeometry.h"
00015 #include "Fireworks/Core/interface/fw3dlego_xbins.h"
00016 #include "Fireworks/Core/interface/fwLog.h"
00017 
00018 #include "DataFormats/FWLite/interface/Handle.h"
00019 #include "DataFormats/EgammaReco/interface/SuperCluster.h"
00020 #include "DataFormats/EcalDetId/interface/EcalSubdetector.h"
00021 
00022 #include "TGeoMatrix.h"
00023 #include "TEveTrans.h"
00024 
00025 #include <utility>
00026 
00027 TEveCaloLego* FWECALDetailViewBuilder::build()
00028 {
00029    // get the hits from the event
00030 
00031    edm::Handle<EcalRecHitCollection> handle_hits;
00032    const EcalRecHitCollection *hits = 0;
00033 
00034    if (fabs(m_eta) < 1.5)
00035    {
00036       try
00037       {
00038          edm::InputTag tag("ecalRecHit", "EcalRecHitsEB");
00039          m_event->getByLabel(tag, handle_hits);
00040          if (handle_hits.isValid())
00041             hits = &*handle_hits;
00042       }
00043       catch (...)
00044       {
00045          fwLog(fwlog::kWarning) <<"no barrel ECAL rechits are available, "
00046             "showing crystal location but not energy" << std::endl;
00047       }
00048    }
00049    else
00050    {
00051       try
00052       {
00053          edm::InputTag tag("ecalRecHit", "EcalRecHitsEE");
00054          m_event->getByLabel(tag, handle_hits);
00055          if (handle_hits.isValid())
00056             hits = &*handle_hits;
00057       }
00058       catch (...)
00059       {
00060          fwLog(fwlog::kWarning) <<"no endcap ECAL rechits are available, "
00061             "showing crystal location but not energy" << std::endl;
00062       }
00063    }
00064      
00065    // data
00066    TEveCaloDataVec* data = new TEveCaloDataVec( 1 + m_colors.size() );
00067    data->RefSliceInfo(0).Setup("hits (not clustered)", 0.0, m_defaultColor );
00068    for( size_t i = 0; i < m_colors.size(); ++i )
00069    {
00070       data->RefSliceInfo(i + 1).Setup( "hits (clustered)", 0.0, m_colors[i] );
00071    }
00072 
00073    if( handle_hits.isValid() ) 
00074       // fill
00075       fillData( hits, data );
00076 
00077    // axis
00078    Double_t etaMin(0), etaMax(0), phiMin(0), phiMax(0);
00079    // it's hard to define properly visible area in X-Y,
00080    // so we rely on auto limits
00081    data->GetEtaLimits(etaMin, etaMax);
00082    data->GetPhiLimits(phiMin, phiMax);
00083    Double_t bl, bh, bw;
00084    Int_t bn, n = 20;
00085    THLimitsFinder::Optimize(etaMin, etaMax, n, bl, bh, bn, bw);
00086    data->SetEtaBins( new TAxis(bn, bl, bh));
00087    THLimitsFinder::Optimize(phiMin, phiMax, n, bl, bh, bn, bw);
00088    data->SetPhiBins( new TAxis(bn, bl, bh));
00089 
00090    // make tower grid
00091    std::vector<double> etaBinsWithinLimits;
00092    etaBinsWithinLimits.push_back(etaMin);
00093    for (unsigned int i=0; i<83; ++i)
00094       if ( fw3dlego::xbins[i] > etaMin && fw3dlego::xbins[i] < etaMax )
00095          etaBinsWithinLimits.push_back(fw3dlego::xbins[i]);
00096    etaBinsWithinLimits.push_back(etaMax);
00097    Double_t* eta_bins = new Double_t[etaBinsWithinLimits.size()];
00098    for (unsigned int i=0; i<etaBinsWithinLimits.size(); ++i)
00099       eta_bins[i] = etaBinsWithinLimits[i];
00100 
00101    std::vector<double> phiBinsWithinLimits;
00102    phiBinsWithinLimits.push_back(phiMin);
00103    for ( double phi = -M_PI; phi < M_PI; phi += M_PI/36 )
00104       if ( phi > phiMin && phi < phiMax ) // it's stupid, I know, but I'm lazy right now
00105          phiBinsWithinLimits.push_back(phi);
00106    phiBinsWithinLimits.push_back(phiMax);
00107    Double_t* phi_bins = new Double_t[phiBinsWithinLimits.size()];
00108    for (unsigned int i=0; i<phiBinsWithinLimits.size(); ++i)
00109       phi_bins[i] = phiBinsWithinLimits[i];
00110    if (fabs(m_eta) > 1.5) {
00111       data->GetEtaBins()->SetTitle("X[cm]");
00112       data->GetPhiBins()->SetTitle("Y[cm]");
00113       data->GetPhiBins()->SetTitleSize(0.03);
00114       data->GetEtaBins()->SetTitleSize(0.03);
00115    } else {
00116       data->SetEtaBins(new TAxis(etaBinsWithinLimits.size()-1,eta_bins));
00117       data->SetPhiBins(new TAxis(phiBinsWithinLimits.size()-1,phi_bins));
00118       data->GetEtaBins()->SetTitleFont(122);
00119       data->GetEtaBins()->SetTitle("h");
00120       data->GetPhiBins()->SetTitleFont(122);
00121       data->GetPhiBins()->SetTitle("f");
00122       data->GetPhiBins()->SetTitleSize(0.05);
00123       data->GetEtaBins()->SetTitleSize(0.05);
00124    }
00125    delete [] eta_bins;
00126    delete [] phi_bins;
00127 
00128    // lego
00129    TEveCaloLego *lego = new TEveCaloLego(data);
00130    lego->SetDrawNumberCellPixels(100);
00131    // scale and translate to real world coordinates
00132    lego->SetEta(etaMin, etaMax);
00133    lego->SetPhiWithRng((phiMin+phiMax)*0.5, (phiMax-phiMin)*0.5); // phi range = 2* phiOffset
00134    Double_t legoScale = ((etaMax - etaMin) < (phiMax - phiMin)) ? (etaMax - etaMin) : (phiMax - phiMin);
00135    lego->InitMainTrans();
00136    lego->RefMainTrans().SetScale(legoScale, legoScale, legoScale*0.5);
00137    lego->RefMainTrans().SetPos((etaMax+etaMin)*0.5, (phiMax+phiMin)*0.5, 0);
00138    lego->SetAutoRebin(kFALSE);
00139    lego->Set2DMode(TEveCaloLego::kValSizeOutline);
00140    lego->SetName("ECALDetail Lego");
00141    return lego;
00142 
00143 }
00144 
00145 void FWECALDetailViewBuilder::setColor(Color_t color, const std::vector<DetId> &detIds)
00146 {
00147 
00148    m_colors.push_back(color);
00149 
00150    // get the slice for this group of detIds
00151    // note that the zeroth slice is the default one (all else)
00152    int slice = m_colors.size();
00153    // take a note of which slice these detids are going to go into
00154    for (size_t i = 0; i < detIds.size(); ++i)
00155       m_detIdsToColor[detIds[i]] = slice;
00156 }
00157 
00158 void
00159 FWECALDetailViewBuilder::showSuperCluster( const reco::SuperCluster &cluster, Color_t color )
00160 {
00161    std::vector<DetId> clusterDetIds;
00162    const std::vector<std::pair<DetId, float> > &hitsAndFractions = cluster.hitsAndFractions();
00163    for (size_t j = 0; j < hitsAndFractions.size(); ++j)
00164    {
00165       clusterDetIds.push_back(hitsAndFractions[j].first);
00166    }
00167 
00168    setColor( color, clusterDetIds );
00169 }
00170 
00171 void
00172 FWECALDetailViewBuilder::showSuperClusters( Color_t color1, Color_t color2 )
00173 {
00174    // get the superclusters from the event
00175    edm::Handle<reco::SuperClusterCollection> collection;
00176 
00177    if( fabs( m_eta ) < 1.5 ) {
00178       try {
00179          m_event->getByLabel(edm::InputTag("correctedHybridSuperClusters"), collection);
00180       }
00181       catch (...)
00182       {
00183          fwLog(fwlog::kWarning) <<"no barrel superclusters are available" << std::endl;
00184       }
00185    } else {
00186       try {
00187          m_event->getByLabel(edm::InputTag("correctedMulti5x5SuperClustersWithPreshower"), collection);
00188       }
00189       catch (...)
00190       {
00191          fwLog(fwlog::kWarning) <<"no endcap superclusters are available" << std::endl;
00192       }
00193    }
00194    if( collection.isValid() )
00195    {
00196       unsigned int colorIndex = 0;
00197       // sort clusters in eta so neighboring clusters have distinct colors
00198       reco::SuperClusterCollection sorted = *collection.product();
00199       std::sort( sorted.begin(), sorted.end(), superClusterEtaLess );
00200       for( size_t i = 0; i < sorted.size(); ++i )
00201       {
00202          if( !(fabs(sorted[i].eta() - m_eta) < (m_size*0.0172)
00203                && fabs(sorted[i].phi() - m_phi) < (m_size*0.0172)) )
00204            continue;
00205 
00206          if( colorIndex %2 == 0 )
00207             showSuperCluster( sorted[i], color1 );
00208          else
00209             showSuperCluster( sorted[i], color2 );
00210          ++colorIndex;
00211       }
00212    }
00213 }
00214 
00215 void
00216 FWECALDetailViewBuilder::fillData( const EcalRecHitCollection *hits,
00217                                    TEveCaloDataVec *data )
00218 {
00219    const float barrelCR = m_size*0.0172; // barrel cell range
00220 
00221    // loop on all the detids
00222    for( EcalRecHitCollection::const_iterator k = hits->begin(), kEnd = hits->end();
00223         k != kEnd; ++k )
00224    {
00225       // get reco geometry
00226       double centerEta = 0;
00227       double centerPhi = 0;
00228       const float* points = m_geom->getCorners( k->id().rawId());
00229       if( points != 0 )
00230       {
00231          TEveVector v;
00232          int j = 0;
00233          for( int i = 0; i < 8; ++i )
00234          {       
00235             v += TEveVector( points[j], points[j + 1], points[j + 2] );
00236             j +=3;
00237          }
00238          centerEta = v.Eta();
00239          centerPhi = v.Phi();
00240       }
00241       else
00242          fwLog( fwlog::kInfo ) << "cannot get geometry for DetId: "<< k->id().rawId() << ". Ignored.\n";
00243       
00244       double size = k->energy() / cosh( centerEta );
00245 
00246       // check what slice to put in
00247       int slice = 0;
00248       std::map<DetId, int>::const_iterator itr = m_detIdsToColor.find(k->id());
00249       if (itr != m_detIdsToColor.end()) slice = itr->second;
00250 
00251       // if in the EB
00252       if( k->id().subdetId() == EcalBarrel )
00253       {
00254          // do phi wrapping
00255          if( centerPhi > m_phi + M_PI) centerPhi -= 2 * M_PI;
00256          if( centerPhi < m_phi - M_PI) centerPhi += 2 * M_PI;
00257 
00258          // check if the hit is in the window to be drawn
00259          if( !( fabs( centerEta - m_eta ) < barrelCR
00260                 && fabs( centerPhi - m_phi ) < barrelCR )) continue;
00261 
00262          double minEta(10), maxEta(-10), minPhi(4), maxPhi(-4);
00263          if( points != 0 )
00264          {
00265             // calorimeter crystalls have slightly non-symetrical form in eta-phi projection
00266             // so if we simply get the largest eta and phi, cells will overlap
00267             // therefore we get a smaller eta-phi range representing the inner square
00268             // we also should use only points from the inner face of the crystal, since
00269             // non-projecting direction of crystals leads to large shift in eta on outter
00270             // face.
00271             int j = 0;
00272             for( unsigned int i = 0; i < 8; ++i )
00273             {
00274                TEveVector crystal( points[j], points[j + 1], points[j + 2] );
00275                j += 3;
00276                double eta = crystal.Eta();
00277                double phi = crystal.Phi();
00278                if ( crystal.Perp() > 135 ) continue;
00279                if ( minEta - eta > 0.01) minEta = eta;
00280                if ( eta - minEta > 0 && eta - minEta < 0.01 ) minEta = eta;
00281                if ( eta - maxEta > 0.01) maxEta = eta;
00282                if ( maxEta - eta > 0 && maxEta - eta < 0.01 ) maxEta = eta;
00283                if ( minPhi - phi > 0.01) minPhi = phi;
00284                if ( phi - minPhi > 0 && phi - minPhi < 0.01 ) minPhi = phi;
00285                if ( phi - maxPhi > 0.01) maxPhi = phi;
00286                if ( maxPhi - phi > 0 && maxPhi - phi < 0.01 ) maxPhi = phi;
00287             }
00288          }
00289          else 
00290          {
00291             double delta = 0.0172 * 0.5;
00292             minEta = centerEta - delta;
00293             maxEta = centerEta + delta;
00294             minPhi = centerPhi - delta;
00295             maxPhi = centerPhi + delta;
00296          }
00297          if( minPhi >= ( m_phi - barrelCR ) && maxPhi <= ( m_phi + barrelCR ) &&
00298              minEta >= ( m_eta - barrelCR ) && maxEta <= ( m_eta + barrelCR ))
00299          {
00300             data->AddTower( minEta, maxEta, minPhi, maxPhi );
00301             data->FillSlice( slice, size );
00302          }
00303          // otherwise in the EE
00304       }
00305       else if( k->id().subdetId() == EcalEndcap )
00306       {
00307          // check if the hit is in the window to be drawn
00308          double crystalSize = m_size * 0.0172;
00309          if( !( fabs( centerEta - m_eta ) < ( crystalSize )
00310                 && fabs( centerPhi - m_phi ) < ( crystalSize )))
00311             continue;
00312 
00313          if( points != 0 )
00314          {
00315             double minX(9999), maxX(-9999), minY(9999), maxY(-9999);
00316             int j = 0;
00317             for( unsigned int i = 0; i < 8; ++i )
00318             {
00319                TEveVector crystal( points[j], points[j + 1], points[j + 2] );
00320                j += 3;
00321                double x = crystal.fX;
00322                double y = crystal.fY;
00323                if( fabs( crystal.fZ ) > 330 ) continue;
00324                if( minX - x > 0.01 ) minX = x;
00325                if( x - maxX > 0.01 ) maxX = x;
00326                if( minY - y > 0.01 ) minY = y;
00327                if( y - maxY > 0.01 ) maxY = y;
00328             }
00329             data->AddTower( minX, maxX, minY, maxY );
00330          }
00331          data->FillSlice( slice, size );
00332       }
00333    } // end loop on hits
00334 
00335    data->DataChanged();
00336  }
00337 
00338 double
00339 FWECALDetailViewBuilder::makeLegend( double x0, double y0,
00340                                      Color_t clustered1, Color_t clustered2,
00341                                      Color_t supercluster
00342                                      )
00343 {
00344    Double_t fontsize = 0.07;
00345    TLatex* latex = new TLatex();
00346    Double_t x = x0;
00347    Double_t y = y0;
00348    Double_t boxH = 0.25*fontsize;
00349    Double_t yStep = 0.04;
00350 
00351    y -= yStep;
00352    latex->DrawLatex(x, y, "Energy types:");
00353    y -= yStep;
00354 
00355    Double_t pos[4];
00356    pos[0] = x+0.05;
00357    pos[2] = x+0.20;
00358 
00359    pos[1] = y; pos[3] = pos[1] + boxH;
00360    FWDetailViewBase::drawCanvasBox(pos, m_defaultColor);
00361    latex->DrawLatex(x+0.25, y, "unclustered");
00362    y -= yStep;
00363    if (clustered1<0) return y;
00364 
00365    pos[1] = y; pos[3] = pos[1] + boxH;
00366    FWDetailViewBase::drawCanvasBox(pos, clustered1);
00367    latex->DrawLatex(x+0.25, y, "clustered");
00368    y -= yStep;
00369    if (clustered2<0) return y;
00370 
00371    pos[1] = y; pos[3] = pos[1] + boxH;
00372    FWDetailViewBase::drawCanvasBox(pos, clustered2);
00373    latex->DrawLatex(x+0.25, y, "clustered");
00374    y -= yStep;
00375    if (supercluster<0) return y;
00376 
00377    pos[1] = y; pos[3] = pos[1] + boxH;
00378    FWDetailViewBase::drawCanvasBox(pos, supercluster);
00379    latex->DrawLatex(x+0.25, y, "super-cluster");
00380    y -= yStep;
00381 
00382    return y;
00383 }