CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/FastSimulation/CaloHitMakers/src/EcalHitMaker.cc

Go to the documentation of this file.
00001 #include "DataFormats/DetId/interface/DetId.h"
00002 #include "DataFormats/EcalDetId/interface/EcalSubdetector.h"
00003 #include "DataFormats/EcalDetId/interface/EBDetId.h"
00004 #include "DataFormats/EcalDetId/interface/EEDetId.h"
00005 
00006 //#include "Geometry/EcalAlgo/interface/EcalBarrelGeometry.h"
00007 //#include "Geometry/EcalAlgo/interface/EcalEndcapGeometry.h"
00008 //#include "Geometry/CaloGeometry/interface/CaloCellGeometry.h"
00009 
00010 #include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
00011 #include "FastSimulation/CaloHitMakers/interface/EcalHitMaker.h"
00012 #include "FastSimulation/CaloGeometryTools/interface/CaloGeometryHelper.h"
00013 #include "FastSimulation/CaloGeometryTools/interface/CrystalWindowMap.h"
00014 #include "FastSimulation/CaloGeometryTools/interface/CaloDirectionOperations.h"
00015 #include "FastSimulation/Event/interface/FSimVertex.h"
00016 #include "FastSimulation/Event/interface/FSimTrack.h"
00017 #include "FastSimulation/CalorimeterProperties/interface/PreshowerLayer1Properties.h"
00018 #include "FastSimulation/CalorimeterProperties/interface/PreshowerLayer2Properties.h"
00019 #include "FastSimulation/CalorimeterProperties/interface/HCALProperties.h"
00020 #include "FastSimulation/Utilities/interface/RandomEngine.h"
00021 //#include "FastSimulation/Utilities/interface/Histos.h"
00022 
00023 //#include "Math/GenVector/Transform3D.h"
00024 #include "FastSimulation/CaloGeometryTools/interface/Transform3DPJ.h"
00025 
00026 #include <algorithm>
00027 #include <cmath>
00028 
00029 typedef ROOT::Math::Plane3D::Vector Vector;
00030 typedef ROOT::Math::Plane3D::Point Point;
00031 typedef ROOT::Math::Transform3DPJ Transform3DR;
00032 
00033 EcalHitMaker::EcalHitMaker(CaloGeometryHelper * theCalo,
00034                            const XYZPoint& ecalentrance, 
00035                            const DetId& cell, int onEcal,
00036                            unsigned size, unsigned showertype,
00037                            const RandomEngine* engine):
00038   CaloHitMaker(theCalo,DetId::Ecal,((onEcal==1)?EcalBarrel:EcalEndcap),onEcal,showertype),
00039   EcalEntrance_(ecalentrance),
00040   onEcal_(onEcal),
00041   myTrack_(NULL),
00042   random(engine)
00043 {
00044 #ifdef FAMOSDEBUG
00045   myHistos = Histos::instance();
00046 #endif
00047   //  myHistos->debug("Constructeur EcalHitMaker");
00048   simulatePreshower_ = true;
00049   X0depthoffset_ = 0. ;
00050   X0PS1_ = 0.;
00051   X0PS2_ = 0.; 
00052   X0PS2EE_ = 0.;
00053   X0ECAL_ = 0.;
00054   X0EHGAP_ = 0.;
00055   X0HCAL_ = 0.;
00056   L0PS1_ = 0.;
00057   L0PS2_ = 0.;
00058   L0PS2EE_ = 0.;
00059   L0ECAL_ = 0.;
00060   L0EHGAP_ = 0.;
00061   L0HCAL_ = 0.;
00062   maxX0_ = 0.;
00063   totalX0_ = 0;
00064   totalL0_ = 0.;
00065   pulledPadProbability_ = 1.;
00066   outsideWindowEnergy_ = 0.;
00067   rearleakage_ = 0.;
00068   bfactor_ = 1.; 
00069   ncrystals_ = 0;
00070 
00071   doreorg_ = !showertype;
00072 
00073   hitmaphasbeencalculated_ = false;
00074 
00075   if(onEcal) 
00076     myCalorimeter->buildCrystal(cell,pivot_);
00077   else
00078     pivot_=Crystal();
00079   central_=onEcal==1;
00080   ecalFirstSegment_=-1;
00081   
00082   myCrystalWindowMap_ = 0; 
00083   // In some cases, a "dummy" grid, not based on a cell, can be built. The previous variables
00084   // should however be initialized. In such a case onEcal=0
00085   if(!onEcal) return;
00086 
00087   // Same size in eta-phi
00088   etasize_ = size;
00089   phisize_ = size;
00090 
00091   // Build the grid
00092   // The result is put in CellsWindow and is ordered by distance to the pivot
00093   myCalorimeter->getWindow(pivot_.getDetId(),size,size,CellsWindow_);
00094 
00095   buildGeometry();
00096   //  std::cout << " Geometry built " << regionOfInterest_.size() << std::endl;
00097 
00098   truncatedGrid_ = CellsWindow_.size()!=(etasize_*phisize_);
00099 
00100   // A local vector of corners
00101   mycorners.resize(4);
00102   corners.resize(4);
00103   
00104 #ifdef DEBUGGW
00105   myHistos->fill("h10",EcalEntrance_.eta(),CellsWindow_.size());
00106   if(onEcal==2) 
00107     {
00108       myHistos->fill("h20",EcalEntrance_.perp(),CellsWindow_.size());
00109       if(EcalEntrance_.perp()>70&&EcalEntrance_.perp()<80&&CellsWindow_.size()<35)
00110         {
00111           std::cout << " Truncated grid " << CellsWindow_.size() << " " << EcalEntrance_.perp() << std::endl;
00112           std::cout << " Pivot " << myCalorimeter->getEcalEndcapGeometry()->getGeometry(pivot_.getDetId())->getPosition().perp();
00113           std::cout << EEDetId(pivot_.getDetId()) << std::endl;
00114 
00115           std::cout << " Test getClosestCell " << EcalEntrance_ << std::endl;
00116           DetId testcell = myCalorimeter->getClosestCell(EcalEntrance_, true, false);
00117           std::cout << " Result "<< EEDetId(testcell) << std::endl;
00118           std::cout << " Position " << myCalorimeter->getEcalEndcapGeometry()->getGeometry(testcell)->getPosition() << std::endl;
00119         }
00120     }
00121 
00122 #endif
00123 
00124 }
00125 
00126 EcalHitMaker::~EcalHitMaker()
00127 {
00128   if (myCrystalWindowMap_ != 0)
00129     {
00130       delete myCrystalWindowMap_;
00131     }
00132 }
00133 
00134 bool 
00135 EcalHitMaker::addHitDepth(double r,double phi,double depth)
00136 {
00137 //  std::cout << " Add hit depth called; Current deph is "  << currentdepth_;
00138 //  std::cout << " Required depth is " << depth << std::endl;
00139   depth+=X0depthoffset_;
00140   double sp(1.);
00141   r*=radiusFactor_;
00142   CLHEP::Hep2Vector point(r*std::cos(phi),r*std::sin(phi));
00143 
00144   unsigned xtal=fastInsideCell(point,sp);  
00145   //  if(cellid.isZero()) std::cout << " cell is Zero " << std::endl;
00146 //  if(xtal<1000) 
00147 //    {
00148 //      std::cout << "Result " << regionOfInterest_[xtal].getX0Back() << " " ;
00149 //      std::cout << depth << std::endl;
00150 //    }
00151 //  myHistos->fill("h5000",depth);
00152   if(xtal<1000)
00153     {
00154       //      myHistos->fill("h5002",regionOfInterest_[xtal].getX0Back(),depth);
00155       //      myHistos->fill("h5003",ecalentrance_.eta(),maxX0_);
00156       if(regionOfInterest_[xtal].getX0Back()>depth) 
00157         {
00158           hits_[xtal]+=spotEnergy;      
00159           //      myHistos->fill("h5005",r);
00160           return true;
00161         }
00162       else
00163         {
00164           rearleakage_+=spotEnergy;
00165         }
00166     }
00167   else
00168     {
00169 //      std::cout << " Return false " << std::endl;
00170 //      std::cout << " Add hit depth called; Current deph is "  << currentdepth_;
00171 //      std::cout << " Required depth is " << depth << std::endl;
00172 //      std::cout << " R = " << r << " " << radiusFactor_ << std::endl; 
00173     }
00174 
00175   outsideWindowEnergy_+=spotEnergy;
00176   return false;
00177 }
00178 
00179 
00180 //bool EcalHitMaker::addHitDepth(double r,double phi,double depth)
00181 //{
00182 //  std::map<unsigned,float>::iterator itcheck=hitMap_.find(pivot_.getDetId().rawId());
00183 //  if(itcheck==hitMap_.end())
00184 //    {
00185 //      hitMap_.insert(std::pair<uint32_t,float>(pivot_.getDetId().rawId(),spotEnergy));
00186 //    }
00187 //  else
00188 //    {
00189 //      itcheck->second+=spotEnergy;
00190 //    }
00191 //  return true;
00192 //}
00193 
00194 bool 
00195 EcalHitMaker::addHit(double r,double phi,unsigned layer)
00196 {
00197   //  std::cout <<" Addhit " << std::endl;
00198   //  std::cout << " Before insideCell " << std::endl;
00199   double sp(1.);
00200   //  std::cout << " Trying to add " << r << " " << phi << " " << radiusFactor_ << std::endl; 
00201   r*=radiusFactor_;
00202   CLHEP::Hep2Vector point(r*std::cos(phi),r*std::sin(phi));
00203   //  std::cout << "point " << point << std::endl;
00204   //  CellID cellid=insideCell(point,sp);
00205   unsigned xtal=fastInsideCell(point,sp);  
00206   //  if(cellid.isZero()) std::cout << " cell is Zero " << std::endl;
00207   if(xtal<1000) 
00208     {
00209       if(sp==1.)
00210         hits_[xtal]+=spotEnergy;        
00211       else      
00212         hits_[xtal]+=(random->flatShoot()<sp)*spotEnergy;
00213       return true;
00214     }
00215 
00216   outsideWindowEnergy_+=spotEnergy;
00217 //  std::cout << " This hit ; r= " << point << " hasn't been added "<<std::endl;
00218 //  std::cout << " Xtal " << xtal << std::endl;
00219 //  for(unsigned ip=0;ip<npadsatdepth_;++ip)
00220 //    {
00221 //      std::cout << padsatdepth_[ip] << std::endl;
00222 //    }
00223   
00224   return false;
00225 }
00226 
00227 // Temporary solution
00228 //bool EcalHitMaker::addHit(double r,double phi,unsigned layer)
00229 //{
00230 //  std::map<unsigned,float>::iterator itcheck=hitMap_.find(pivot_.getDetId().rawId());
00231 //  if(itcheck==hitMap_.end())
00232 //    {
00233 //      hitMap_.insert(std::pair<uint32_t,float>(pivot_.getDetId().rawId(),spotEnergy));
00234 //    }
00235 //  else
00236 //    {
00237 //      itcheck->second+=spotEnergy;
00238 //    }
00239 //  return true;
00240 //}
00241 
00242 
00243 unsigned 
00244 EcalHitMaker::fastInsideCell(const CLHEP::Hep2Vector & point,double & sp,bool debug) 
00245 {
00246 
00247   //  debug = true;
00248   bool found=false;
00249   unsigned niter=0;
00250   // something clever has to be implemented here
00251   unsigned d1,d2;
00252   convertIntegerCoordinates(point.x(),point.y(),d1,d2);
00253   //  std::cout << "Fastinside cell " << point.x() << " " <<  point.y() << " " << d1 << " "<< d2 << " " << nx_ << " " << ny_ << std::endl;
00254   if(d1>=nx_||d2>=ny_) 
00255     {
00256       //      std::cout << " Not in the map " <<std::endl;
00257       return 9999;
00258     }
00259   unsigned cell=myCrystalNumberArray_[d1][d2];
00260   // We are likely to be lucky
00261   //  std::cout << " Got the cell " << cell << std::endl;
00262   if (validPads_[cell]&&padsatdepth_[cell].inside(point)) 
00263     {
00264       //      std::cout << " We are lucky " << cell << std::endl;
00265       sp = padsatdepth_[cell].survivalProbability();
00266       return cell;
00267     }
00268   
00269   //  std::cout << "Starting the loop " << std::endl;
00270   bool status(true);
00271   const std::vector<unsigned>& localCellVector(myCrystalWindowMap_->getCrystalWindow(cell,status));
00272   if(status) 
00273     {
00274       unsigned size=localCellVector.size();      
00275       //      std::cout << " Starting from " << EBDetId(regionOfInterest_[cell].getDetId()) << std::endl;
00276       //      const std::vector<DetId>& neighbours=myCalorimeter->getNeighbours(regionOfInterest_[cell].getDetId());
00277 //      std::cout << " The neighbours are " << std::endl;
00278 //      for(unsigned ic=0;ic<neighbours.size(); ++ic)
00279 //      {
00280 //        std::cout << EBDetId(neighbours[ic]) << std::endl;
00281 //      }
00282 //      std::cout << " Done " << std::endl;
00283       for(unsigned ic=0;ic<8&&ic<size;++ic)
00284         {
00285           unsigned iq=localCellVector[ic];
00286 //        std::cout << " Testing " << EBDetId(regionOfInterest_[iq].getDetId()) << std::endl; ; 
00287 //        std::cout << " " << iq << std::endl;
00288 //        std::cout << padsatdepth_[iq] ;
00289           if(validPads_[iq]&&padsatdepth_[iq].inside(point))
00290             {
00291               //              std::cout << " Yes " << std::endl;
00292               //              myHistos->fill("h1000",niter);
00293               sp = padsatdepth_[iq].survivalProbability();
00294               //              std::cout << "Finished the loop " << niter << std::endl;
00295               //              std::cout << "Inside " << std::endl;
00296               return iq;
00297             }
00298           //      std::cout << " Not inside " << std::endl;
00299           //      std::cout << "No " << std::endl;
00300           ++niter;
00301         }
00302           }
00303   if(debug) std::cout << " not found in a quad, let's check the " << ncrackpadsatdepth_ << " cracks " << std::endl;
00304   //  std::cout << "Finished the loop " << niter << std::endl;
00305   // Let's check the cracks 
00306   //  std::cout << " Let's check the cracks " << ncrackpadsatdepth_ << " " << crackpadsatdepth_.size() << std::endl;
00307   unsigned iquad=0;
00308   unsigned iquadinside=999;
00309   while(iquad<ncrackpadsatdepth_&&!found)
00310     {
00311       //      std::cout << " Inside the while " << std::endl;
00312       if(crackpadsatdepth_[iquad].inside(point)) 
00313         {
00314           iquadinside=iquad;
00315           found=true;
00316           sp = crackpadsatdepth_[iquad].survivalProbability();
00317         }
00318       ++iquad;
00319       ++niter;
00320     }
00321   //  myHistos->fill("h1002",niter);
00322   if(!found&&debug) std::cout << " Not found in the cracks " << std::endl;
00323   return (found) ? crackpadsatdepth_[iquadinside].getNumber(): 9999;
00324 }
00325 
00326 
00327 void 
00328 EcalHitMaker::setTrackParameters(const XYZNormal& normal,
00329                                  double X0depthoffset,
00330                                  const FSimTrack& theTrack)
00331 {
00332   //  myHistos->debug("setTrackParameters");
00333   //  std::cout << " Track " << theTrack << std::endl;
00334   intersections_.clear();
00335   // This is certainly enough
00336   intersections_.reserve(50);
00337   myTrack_=&theTrack;
00338   normal_=normal.Unit();
00339   X0depthoffset_=X0depthoffset;
00340   cellLine(intersections_);
00341   buildSegments(intersections_);
00342 //  std::cout << " Segments " << segments_.size() << std::endl;
00343 //  for(unsigned ii=0; ii<segments_.size() ; ++ii)
00344 //    {
00345 //      std::cout << segments_[ii] << std::endl;
00346 //    }
00347 
00348 
00349   // This is only needed in case of electromagnetic showers 
00350   if(EMSHOWER&&onEcal_&&ecalTotalX0()>0.)
00351     {
00352       //      std::cout << "Total X0  " << ecalTotalX0() << std::endl;
00353       for(unsigned ic=0;ic<ncrystals_;++ic)
00354         {
00355           for(unsigned idir=0;idir<4;++idir)
00356             {
00357               XYZVector norm=regionOfInterest_[ic].exitingNormal(CaloDirectionOperations::Side(idir));
00358               regionOfInterest_[ic].crystalNeighbour(idir).setToBeGlued((norm.Dot(normal_)<0.));
00359             }
00360           // Now calculate the distance in X0 of the back sides of the crystals
00361           // (only for EM showers)
00362           if(EMSHOWER)
00363             {
00364               XYZVector dir=regionOfInterest_[ic].getBackCenter()-segments_[ecalFirstSegment_].entrance();
00365               double dist=dir.Dot(normal_);
00366               double absciss= dist+segments_[ecalFirstSegment_].sEntrance();
00367               std::vector<CaloSegment>::const_iterator segiterator;
00368               // First identify the correct segment
00369               //      std::cout << " Crystal " << ic  << regionOfInterest_[ic].getBackCenter() ;
00370               //      std::cout << " Entrance : " << segments_[ecalFirstSegment_].entrance()<< std::endl;
00371               //      std::cout << " Looking for the segment " << dist << std::endl;
00372               segiterator = find_if(segments_.begin(),segments_.end(),CaloSegment::inSegment(absciss));
00373               //      std::cout << " Done " << std::endl;
00374               if(segiterator==segments_.end() )
00375                 {
00376                   // in this case, we won't have any problem. No need to 
00377                   // calculate the real depth. 
00378                   regionOfInterest_[ic].setX0Back(9999);
00379                 }
00380               else
00381                 {
00382                   DetId::Detector det(segiterator->whichDetector());
00383                   if(det!=DetId::Ecal)
00384                     {
00385                       regionOfInterest_[ic].setX0Back(9999);
00386                     }
00387                   else
00388                     {
00389                       double x0=segiterator->x0FromCm(dist);
00390                       if(x0<maxX0_) maxX0_=x0;
00391                       regionOfInterest_[ic].setX0Back(x0);
00392                     }
00393                 }
00394               //  myHistos->fill("h4000",ecalentrance_.eta(), regionOfInterest_[ic].getX0Back());
00395               //}
00396               //      else
00397               //{
00398               //   // in this case, we won't have any problem. No need to 
00399               //  // calculate the real depth. 
00400               //  regionOfInterest_[ic].setX0Back(9999);
00401               //}
00402             }//EMSHOWER  
00403         } // ndir
00404       //      myHistos->fill("h6000",segments_[ecalFirstSegment_].entrance().eta(),maxX0_);
00405     }
00406   //  std::cout << "Leaving setTrackParameters" << std::endl
00407 }
00408 
00409 
00410 void 
00411 EcalHitMaker::cellLine(std::vector<CaloPoint>& cp) 
00412 {
00413   cp.clear();
00414   //  if(myTrack->onVFcal()!=2)
00415   //    {
00416   if(!central_&&onEcal_&&simulatePreshower_) preshowerCellLine(cp);
00417   if(onEcal_)ecalCellLine(EcalEntrance_,EcalEntrance_+normal_,cp);
00418   //    }
00419   
00420   XYZPoint vertex(myTrack_->vertex().position().Vect());
00421 
00422   //sort the points by distance (in the ECAL they are not necessarily ordered)
00423   XYZVector dir(0.,0.,0.);
00424   if(myTrack_->onLayer1())
00425     {
00426       vertex=(myTrack_->layer1Entrance().vertex()).Vect();
00427       dir=myTrack_->layer1Entrance().Vect().Unit();
00428     }
00429   else if(myTrack_->onLayer2())
00430     {
00431       vertex=(myTrack_->layer2Entrance().vertex()).Vect();
00432       dir=myTrack_->layer2Entrance().Vect().Unit();
00433     }  
00434   else if(myTrack_->onEcal())
00435     {
00436       vertex=(myTrack_->ecalEntrance().vertex()).Vect();
00437       dir=myTrack_->ecalEntrance().Vect().Unit();
00438     }
00439   else if(myTrack_->onHcal())
00440     {
00441       vertex=(myTrack_->hcalEntrance().vertex()).Vect();
00442       dir=myTrack_->hcalEntrance().Vect().Unit();
00443     }
00444   else if(myTrack_->onVFcal()==2)
00445     {
00446       vertex=(myTrack_->vfcalEntrance().vertex()).Vect();
00447       dir=myTrack_->vfcalEntrance().Vect().Unit();
00448     }
00449   else
00450     {
00451       std::cout << " Problem with the grid " << std::endl;
00452     }
00453  
00454   // Move the vertex for distance comparison (5cm)
00455   vertex -= 5.*dir;
00456   CaloPoint::DistanceToVertex myDistance(vertex);
00457   sort(cp.begin(),cp.end(),myDistance);
00458   
00459   // The intersections with the HCAL shouldn't need to be sorted
00460   // with the N.I it is actually a source of problems
00461   hcalCellLine(cp);
00462 
00463 //  std::cout << " Intersections ordered by distance to " << vertex << std::endl;
00464 //
00465 //  for (unsigned ic=0;ic<cp.size();++ic)
00466 //    {
00467 //      XYZVector t=cp[ic]-vertex;
00468 //      std::cout << cp[ic] << " " << t.mag() << std::endl;
00469 //    }
00470 }
00471 
00472 
00473 void 
00474 EcalHitMaker::preshowerCellLine(std::vector<CaloPoint>& cp) const
00475 {
00476   //  FSimEvent& mySimEvent = myEventMgr->simSignal();
00477   //  FSimTrack myTrack = mySimEvent.track(fsimtrack_);
00478   //  std::cout << "FsimTrack " << fsimtrack_<< std::endl;
00479   //  std::cout << " On layer 1 " << myTrack.onLayer1() << std::endl;
00480   // std::cout << " preshowerCellLine " << std::endl; 
00481   if(myTrack_->onLayer1())
00482     {
00483       XYZPoint point1=(myTrack_->layer1Entrance().vertex()).Vect();
00484       double phys_eta=myTrack_->layer1Entrance().eta();
00485       double cmthickness = 
00486         myCalorimeter->layer1Properties(1)->thickness(phys_eta);
00487 
00488       if(cmthickness>0)
00489         {
00490           XYZVector dir=myTrack_->layer1Entrance().Vect().Unit();
00491           XYZPoint point2=point1+dir*cmthickness;
00492           
00493           CaloPoint cp1(DetId::Ecal,EcalPreshower,1,point1);
00494           CaloPoint cp2(DetId::Ecal,EcalPreshower,1,point2);
00495           cp.push_back(cp1);
00496           cp.push_back(cp2);
00497         }
00498       else
00499         {
00500           //      std::cout << "Track on ECAL " << myTrack.EcalEntrance_().vertex()*0.1<< std::endl;
00501         }
00502     }
00503 
00504   //  std::cout << " On layer 2 " << myTrack.onLayer2() << std::endl;
00505   if(myTrack_->onLayer2())
00506     {
00507       XYZPoint point1=(myTrack_->layer2Entrance().vertex()).Vect();
00508       double phys_eta=myTrack_->layer2Entrance().eta();
00509       double cmthickness = 
00510         myCalorimeter->layer2Properties(1)->thickness(phys_eta);
00511       if(cmthickness>0)
00512         {
00513           XYZVector dir=myTrack_->layer2Entrance().Vect().Unit();
00514           XYZPoint point2=point1+dir*cmthickness;
00515           
00516 
00517           CaloPoint cp1(DetId::Ecal,EcalPreshower,2,point1);
00518           CaloPoint cp2(DetId::Ecal,EcalPreshower,2,point2);
00519 
00520           cp.push_back(cp1);
00521           cp.push_back(cp2);
00522         }
00523       else
00524         {
00525           //      std::cout << "Track on ECAL " << myTrack.EcalEntrance_().vertex()*0.1 << std::endl;
00526         }
00527     }
00528   //  std::cout << " Exit preshower CellLine " << std::endl;
00529 }
00530 
00531 void 
00532 EcalHitMaker::hcalCellLine(std::vector<CaloPoint>& cp) const
00533 {
00534   //  FSimEvent& mySimEvent = myEventMgr->simSignal();
00535   //  FSimTrack myTrack = mySimEvent.track(fsimtrack_);
00536   int onHcal=myTrack_->onHcal();
00537 
00538   if(onHcal<=2&&onHcal>0)
00539     {
00540       XYZPoint point1=(myTrack_->hcalEntrance().vertex()).Vect();
00541 
00542       double eta=point1.eta();
00543       // HCAL thickness in cm (assuming that the particle is coming from 000)
00544       double thickness= myCalorimeter->hcalProperties(onHcal)->thickness(eta);
00545       cp.push_back(CaloPoint(DetId::Hcal,point1));
00546       XYZVector dir=myTrack_->hcalEntrance().Vect().Unit();
00547       XYZPoint point2=point1+dir*thickness;
00548 
00549       cp.push_back(CaloPoint(DetId::Hcal,point2));
00550       
00551     }
00552   int onVFcal=myTrack_->onVFcal();
00553   if(onVFcal==2)
00554     {
00555       XYZPoint point1=(myTrack_->vfcalEntrance().vertex()).Vect();
00556       double eta=point1.eta();
00557       // HCAL thickness in cm (assuming that the particle is coming from 000)
00558       double thickness= myCalorimeter->hcalProperties(3)->thickness(eta);
00559       cp.push_back(CaloPoint(DetId::Hcal,point1));
00560       XYZVector dir=myTrack_->vfcalEntrance().Vect().Unit();
00561       if(thickness>0)
00562         {
00563           XYZPoint point2=point1+dir*thickness;
00564           cp.push_back(CaloPoint(DetId::Hcal,point2));
00565         }
00566 
00567     }
00568 }
00569 
00570 void 
00571 EcalHitMaker::ecalCellLine(const XYZPoint& a,const XYZPoint& b,std::vector<CaloPoint>& cp) 
00572 {
00573   //  std::vector<XYZPoint> corners;
00574   //  corners.resize(4);
00575   unsigned ic=0;
00576   double t;
00577   XYZPoint xp;
00578   DetId c_entrance,c_exit;
00579   bool entrancefound(false),exitfound(false);
00580   //  std::cout << " Look for intersections " << ncrystals_ << std::endl;
00581   //  std::cout << " regionOfInterest_ " << truncatedGrid_ << " " << regionOfInterest_.size() << std::endl;
00582   // try to determine the number of crystals to test
00583   // First determine the incident angle
00584   double angle=std::acos(normal_.Dot(regionOfInterest_[0].getAxis().Unit()));
00585 
00586   //  std::cout << " Normal " << normal_<< " Axis " << regionOfInterest_[0].getAxis().Unit() << std::endl;
00587   double backdistance=std::sqrt(regionOfInterest_[0].getAxis().mag2())*std::tan(angle);
00588   // 1/2.2cm = 0.45
00589 //   std::cout << " Angle " << angle << std::endl;
00590 //   std::cout << " Back distance " << backdistance << std::endl;
00591   unsigned ncrystals=(unsigned)(backdistance*0.45);
00592   unsigned highlim=(ncrystals+4);
00593   highlim*=highlim;
00594   if(highlim>ncrystals_) highlim=ncrystals_;
00595   //  unsigned lowlim=(ncrystals>2)? (ncrystals-2):0;
00596   //  std::cout << " Ncrys " << ncrystals << std::endl;
00597   
00598   
00599   while(ic<ncrystals_&&(ic<highlim||!exitfound))
00600     {
00601       // Check front side
00602       //      if(!entrancefound)
00603         {
00604           const Plane3D& plan=regionOfInterest_[ic].getFrontPlane();
00605 //        XYZVector axis1=(plan.Normal());
00606 //        XYZVector axis2=regionOfInterest_[ic].getFirstEdge();
00607           xp=intersect(plan,a,b,t,false);
00608           regionOfInterest_[ic].getFrontSide(corners);
00609           //      CrystalPad pad(9999,onEcal_,corners,regionOfInterest_[ic].getCorner(0),axis1,axis2);
00610           //      if(pad.globalinside(xp)) 
00611           if(inside3D(corners,xp))
00612             {
00613               cp.push_back(CaloPoint(regionOfInterest_[ic].getDetId(),UP,xp));
00614               entrancefound=true;
00615               c_entrance=regionOfInterest_[ic].getDetId();
00616               //      myHistos->fill("j12",highlim,ic);
00617             }
00618         }
00619       
00620       // check rear side
00621         //      if(!exitfound)
00622         {
00623           const Plane3D& plan=regionOfInterest_[ic].getBackPlane();
00624 //        XYZVector axis1=(plan.Normal());
00625 //        XYZVector axis2=regionOfInterest_[ic].getFifthEdge();
00626           xp=intersect(plan,a,b,t,false);
00627           regionOfInterest_[ic].getBackSide(corners);
00628           //      CrystalPad pad(9999,onEcal_,corners,regionOfInterest_[ic].getCorner(4),axis1,axis2);
00629           //      if(pad.globalinside(xp)) 
00630           if(inside3D(corners,xp))
00631             {
00632               cp.push_back(CaloPoint(regionOfInterest_[ic].getDetId(),DOWN,xp));
00633               exitfound=true;
00634               c_exit=regionOfInterest_[ic].getDetId();
00635               //              std::cout << " Crystal : " << ic << std::endl;
00636               //              myHistos->fill("j10",highlim,ic);
00637             }
00638         }
00639       
00640       if(entrancefound&&exitfound&&c_entrance==c_exit) return;
00641       // check lateral sides 
00642       for(unsigned iside=0;iside<4;++iside)
00643         {
00644           const Plane3D& plan=regionOfInterest_[ic].getLateralPlane(iside);
00645           xp=intersect(plan,a,b,t,false);
00646 //        XYZVector axis1=(plan.Normal());
00647 //        XYZVector axis2=regionOfInterest_[ic].getLateralEdge(iside);
00648           regionOfInterest_[ic].getLateralSide(iside,corners);
00649           //      CrystalPad pad(9999,onEcal_,corners,regionOfInterest_[ic].getCorner(iside),axis1,axis2);
00650           //      if(pad.globalinside(xp)) 
00651           if(inside3D(corners,xp))
00652             {
00653               cp.push_back(CaloPoint(regionOfInterest_[ic].getDetId(),CaloDirectionOperations::Side(iside),xp)); 
00654               //              std::cout << cp[cp.size()-1] << std::endl;
00655             }     
00656         }
00657       // Go to next crystal 
00658       ++ic;
00659     }    
00660 }
00661 
00662 
00663 void 
00664 EcalHitMaker::buildSegments(const std::vector<CaloPoint>& cp)
00665 {
00666   //  myHistos->debug();
00667   //  TimeMe theT("FamosGrid::buildSegments");
00668   unsigned size=cp.size();
00669   if(size%2!=0) 
00670     {
00671       //      std::cout << " There is a problem " << std::endl;
00672       return;
00673     }
00674   //  myHistos->debug();
00675   unsigned nsegments=size/2;
00676   segments_.reserve(nsegments);
00677   if (size==0) return;
00678   // curv abs
00679   double s=0.;
00680   double sX0=0.;
00681   double sL0=0.;
00682   
00683   unsigned ncrossedxtals = 0;
00684   unsigned is=0;
00685   while(is<nsegments)
00686     {
00687 
00688       if(cp[2*is].getDetId()!=cp[2*is+1].getDetId()&&
00689          cp[2*is].whichDetector()!=DetId::Hcal&&
00690          cp[2*is+1].whichDetector()!=DetId::Hcal) 
00691         {
00692 //        std::cout << " Problem with the segments " << std::endl;
00693 //        std::cout << cp[2*is].whichDetector() << " " << cp[2*is+1].whichDetector() << std::endl;
00694 //        std::cout << is << " " <<cp[2*is].getDetId().rawId() << std::endl; 
00695 //        std::cout << (2*is+1) << " " <<cp[2*is+1].getDetId().rawId() << std::endl; 
00696           ++is;
00697           continue;
00698         }
00699 
00700       // Check if it is a Preshower segment - Layer 1 
00701       // One segment per layer, nothing between
00702       //      myHistos->debug("Just avant Preshower"); 
00703       if(cp[2*is].whichDetector()==DetId::Ecal && cp[2*is].whichSubDetector()==EcalPreshower && cp[2*is].whichLayer()==1)
00704         {
00705           if(cp[2*is+1].whichDetector()==DetId::Ecal && cp[2*is+1].whichSubDetector()==EcalPreshower && cp[2*is+1].whichLayer()==1)
00706             {
00707               CaloSegment preshsegment(cp[2*is],cp[2*is+1],s,sX0,sL0,CaloSegment::PS,myCalorimeter);
00708               segments_.push_back(preshsegment);
00709               //              std::cout << " Added (1-1)" << preshsegment << std::endl;
00710               s+=preshsegment.length();
00711               sX0+=preshsegment.X0length();
00712               sL0+=preshsegment.L0length();
00713               X0PS1_+=preshsegment.X0length();
00714               L0PS1_+=preshsegment.L0length();
00715             }
00716           else
00717             {
00718               std::cout << " Strange segment between Preshower1 and " << cp[2*is+1].whichDetector();
00719               std::cout << std::endl;
00720             }
00721           ++is;
00722           continue;
00723         }
00724 
00725       // Check if it is a Preshower segment - Layer 2 
00726       // One segment per layer, nothing between
00727       if(cp[2*is].whichDetector()==DetId::Ecal && cp[2*is].whichSubDetector()==EcalPreshower && cp[2*is].whichLayer()==2)
00728         {
00729           if(cp[2*is+1].whichDetector()==DetId::Ecal && cp[2*is+1].whichSubDetector()==EcalPreshower && cp[2*is+1].whichLayer()==2)
00730             {
00731               CaloSegment preshsegment(cp[2*is],cp[2*is+1],s,sX0,sL0,CaloSegment::PS,myCalorimeter);
00732               segments_.push_back(preshsegment);
00733               //              std::cout << " Added (1-2)" << preshsegment << std::endl;
00734               s+=preshsegment.length();
00735               sX0+=preshsegment.X0length();
00736               sL0+=preshsegment.L0length();
00737               X0PS2_+=preshsegment.X0length();
00738               L0PS2_+=preshsegment.L0length();
00739 
00740               // material between preshower and EE
00741               if(is<(nsegments-1) && cp[2*is+2].whichDetector()==DetId::Ecal && cp[2*is+2].whichSubDetector()==EcalEndcap)
00742                                 {
00743                   CaloSegment gapsef(cp[2*is+1],cp[2*is+2],s,sX0,sL0,CaloSegment::PSEEGAP,myCalorimeter);
00744                   segments_.push_back(gapsef);
00745                   s+=gapsef.length();     
00746                   sX0+=gapsef.X0length();                                                                                          
00747                   sL0+=gapsef.L0length();                                                                                          
00748                   X0PS2EE_+=gapsef.X0length();                        
00749                   L0PS2EE_+=gapsef.L0length();      
00750                   //              std::cout << " Created  a segment " << gapsef.length()<< " " << gapsef.X0length()<< std::endl;
00751                 }             
00752             }
00753           else
00754             {
00755               std::cout << " Strange segment between Preshower2 and " << cp[2*is+1].whichDetector();
00756               std::cout << std::endl;
00757             }
00758           ++is;
00759           continue;
00760         }
00761       // Now deal with the ECAL
00762       // One segment in each crystal. Segment corresponding to cracks/gaps are added
00763       //      myHistos->debug("Just avant ECAL"); 
00764       if(cp[2*is].whichDetector()==DetId::Ecal && (cp[2*is].whichSubDetector()==EcalBarrel || cp[2*is].whichSubDetector()==EcalEndcap))
00765         {
00766           if(cp[2*is+1].whichDetector()==DetId::Ecal && (cp[2*is+1].whichSubDetector()==EcalBarrel || cp[2*is+1].whichSubDetector()==EcalEndcap) )
00767             {
00768               DetId cell2=cp[2*is+1].getDetId();
00769               // set the real entrance
00770               if (ecalFirstSegment_<0) ecalFirstSegment_=segments_.size();
00771 
00772               // !! Approximatiom : the first segment is always in a crystal
00773               if(cp[2*is].getDetId()==cell2)
00774                 {
00775                   CaloSegment segment(cp[2*is],cp[2*is+1],s,sX0,sL0,CaloSegment::PbWO4,myCalorimeter);
00776                  segments_.push_back(segment);
00777                  // std::cout << " Added (2)" << segment << std::endl;
00778                  s+=segment.length();
00779                  sX0+=segment.X0length();
00780                  sL0+=segment.L0length(); 
00781                  X0ECAL_+=segment.X0length();
00782                  L0ECAL_+=segment.L0length();
00783                  ++ncrossedxtals;
00784                  ++is; 
00785                 }
00786               else
00787                 {
00788                   std::cout << " One more bug in the segment " <<std::endl;
00789                   ++is;
00790                 }
00791               // Now check if a gap or crack should be added
00792               if(is>0 && is<nsegments)
00793                 {                 
00794                   DetId cell3=cp[2*is].getDetId();
00795                   if(cp[2*is].whichDetector()!=DetId::Hcal) 
00796                     {
00797                       // Crack inside the ECAL
00798                       bool bordercrossing=myCalorimeter->borderCrossing(cell2,cell3);
00799                       CaloSegment cracksegment(cp[2*is-1],cp[2*is],s,sX0,sL0,(bordercrossing)?CaloSegment::CRACK:CaloSegment::GAP,myCalorimeter);
00800                       segments_.push_back(cracksegment);
00801                       s+=cracksegment.length();
00802                       sX0+=cracksegment.X0length();
00803                       sL0+=cracksegment.L0length();
00804                       X0ECAL_+=cracksegment.X0length();
00805                       L0ECAL_+=cracksegment.L0length();
00806                       //   std::cout <<" Added(3) "<< cracksegment << std::endl;
00807                     }
00808                   else
00809                     {
00810                       // a segment corresponding to ECAL/HCAL transition should be
00811                       // added here
00812                       CaloSegment cracksegment(cp[2*is-1],cp[2*is],s,sX0,sL0,CaloSegment::ECALHCALGAP,myCalorimeter);
00813                       segments_.push_back(cracksegment);
00814                       s+=cracksegment.length();
00815                       sX0+=cracksegment.X0length();
00816                       sL0+=cracksegment.L0length();
00817                       X0EHGAP_+=cracksegment.X0length();
00818                       L0EHGAP_+=cracksegment.L0length();
00819                     }
00820                 }
00821               continue;
00822             }
00823           else
00824             {
00825               std::cout << " Strange segment between " << cp[2*is].whichDetector();
00826               std::cout << " and " << cp[2*is+1].whichDetector() << std::endl;
00827               ++is;
00828               continue;
00829             }     
00830         }
00831       //      myHistos->debug("Just avant HCAL"); 
00832       // HCAL
00833       if(cp[2*is].whichDetector()==DetId::Hcal&&cp[2*is+1].whichDetector()==DetId::Hcal)
00834         {
00835           CaloSegment segment(cp[2*is],cp[2*is+1],s,sX0,sL0,CaloSegment::HCAL,myCalorimeter);
00836           segments_.push_back(segment);
00837           s+=segment.length();
00838           sX0+=segment.X0length();
00839           sL0+=segment.L0length(); 
00840           X0HCAL_+=segment.X0length();
00841           L0HCAL_+=segment.L0length();
00842           //      std::cout <<" Added(4) "<< segment << std::endl;
00843           ++is; 
00844         }
00845     }
00846 //  std::cout << " PS1 " << X0PS1_ << " " << L0PS1_ << std::endl;
00847 //  std::cout << " PS2 " << X0PS2_ << " " << L0PS2_ << std::endl;
00848 //  std::cout << " ECAL " << X0ECAL_ << " " << L0ECAL_ << std::endl;
00849 //  std::cout << " HCAL " << X0HCAL_ << " " << L0HCAL_ << std::endl;
00850   
00851   totalX0_ = X0PS1_+X0PS2_+X0PS2EE_+X0ECAL_+X0EHGAP_+X0HCAL_;
00852   totalL0_ = L0PS1_+L0PS2_+L0PS2EE_+L0ECAL_+L0EHGAP_+L0HCAL_;
00853   //  myHistos->debug("Just avant le fill"); 
00854 
00855   #ifdef DEBUGCELLLINE
00856   myHistos->fill("h200",fabs(EcalEntrance_.eta()),X0ECAL_);
00857   myHistos->fill("h210",EcalEntrance_.phi(),X0ECAL_);
00858   if(X0ECAL_<20)
00859     myHistos->fill("h212",EcalEntrance_.phi(),X0ECAL_);
00860 //  if(X0ECAL_<1.) 
00861 //    {
00862 //      for(unsigned ii=0; ii<segments_.size() ; ++ii)
00863 //      {
00864 //        std::cout << segments_[ii] << std::endl;
00865 //      }
00866 //    }
00867   myHistos->fillByNumber("h30",ncrossedxtals,EcalEntrance_.eta(),X0ECAL_);
00868   
00869   double zvertex = myTrack_->vertex().position().z();
00870 
00871   myHistos->fill("h310",EcalEntrance_.eta(),X0ECAL_);
00872   if(X0ECAL_<22)   myHistos->fill("h410",EcalEntrance_.phi());
00873   myHistos->fill("h400",zvertex,X0ECAL_);
00874   #endif
00875   //  std::cout << " Finished the segments " << std::endl;
00876     
00877 }
00878 
00879 void 
00880 EcalHitMaker::buildGeometry()
00881 {
00882   configuredGeometry_ = false;
00883   ncrystals_ = CellsWindow_.size();
00884   // create the vector with of pads with the appropriate size
00885   padsatdepth_.resize(ncrystals_);
00886   
00887   // This is fully correct in the barrel. 
00888   ny_= phisize_;
00889   nx_=ncrystals_/ny_;
00890   std::vector<unsigned> empty;
00891   empty.resize(ny_,0);
00892   myCrystalNumberArray_.reserve((unsigned)nx_);
00893   for(unsigned inx=0;inx<(unsigned)nx_;++inx)
00894     {      
00895       myCrystalNumberArray_.push_back(empty);
00896     }
00897 
00898   hits_.resize(ncrystals_,0.);
00899   regionOfInterest_.clear();
00900   regionOfInterest_.resize(ncrystals_);
00901   validPads_.resize(ncrystals_);
00902   for(unsigned ic=0;ic<ncrystals_;++ic)
00903     {
00904       myCalorimeter->buildCrystal(CellsWindow_[ic],regionOfInterest_[ic]);
00905       regionOfInterest_[ic].setNumber(ic);
00906       DetIdMap_.insert(std::pair<DetId,unsigned>(CellsWindow_[ic],ic));     
00907     }
00908   
00909   // Computes the map of the neighbours
00910   myCrystalWindowMap_ = new CrystalWindowMap(myCalorimeter,regionOfInterest_);
00911 }
00912 
00913 
00914 
00915 // depth is in X0 , L0 (depending on EMSHOWER/HADSHOWER) or in CM if inCM
00916 bool 
00917 EcalHitMaker::getPads(double depth,bool inCm) 
00918 {
00919   //std::cout << " New depth " << depth << std::endl;
00920   // The first time, the relationship between crystals must be calculated
00921   // but only in the case of EM showers
00922 
00923   if(EMSHOWER && !configuredGeometry_) configureGeometry();
00924 
00925 
00926   radiusFactor_ = (EMSHOWER) ? moliereRadius*radiusCorrectionFactor_:interactionLength;
00927   detailedShowerTail_ = false;
00928   if(EMSHOWER)
00929     currentdepth_ = depth+X0depthoffset_;
00930   else
00931     currentdepth_ = depth;
00932   
00933 //  if(currentdepth_>maxX0_+ps1TotalX0()+ps2TotalX0()) 
00934 //    {
00935 //      currentdepth_=maxX0_+ps1TotalX0()+ps2TotalX0()-1.; // the -1 is for safety
00936 //      detailedShowerTail_=true;
00937 //    }
00938     
00939 //  std::cout << " FamosGrid::getQuads " << currentdepth_ << " " << maxX0_ << std::endl;
00940 
00941   ncrackpadsatdepth_=0;
00942   
00943   xmin_=ymin_=999;
00944   xmax_=ymax_=-999;
00945   double locxmin,locxmax,locymin,locymax;
00946 
00947   // Get the depth of the pivot
00948   std::vector<CaloSegment>::const_iterator segiterator;
00949   // First identify the correct segment
00950 
00951   if(inCm) // centimeter
00952     {
00953       segiterator = find_if(segments_.begin(),segments_.end(),CaloSegment::inSegment(currentdepth_));
00954     }
00955   else
00956     {
00957       // EM shower 
00958       if(EMSHOWER)
00959         segiterator = find_if(segments_.begin(),segments_.end(),CaloSegment::inX0Segment(currentdepth_));
00960       
00961       //Hadron shower 
00962       if(HADSHOWER)
00963         segiterator = find_if(segments_.begin(),segments_.end(),CaloSegment::inL0Segment(currentdepth_));
00964     }
00965   if(segiterator==segments_.end()) 
00966     {
00967       std::cout << " FamosGrid: Could not go at such depth " << depth << std::endl;
00968       std::cout << " EMSHOWER " << EMSHOWER << std::endl;
00969       std::cout << " Track " << *myTrack_ << std::endl;
00970       std::cout << " Segments " << segments_.size() << std::endl;
00971       for(unsigned ii=0; ii<segments_.size() ; ++ii)
00972         {
00973           std::cout << segments_[ii] << std::endl;
00974         }
00975       
00976       return false;
00977     }
00978   //  std::cout << *segiterator << std::endl;
00979   
00980   if(segiterator->whichDetector()!=DetId::Ecal)
00981     {
00982       std::cout << " In  " << segiterator->whichDetector() << std::endl;
00983       //      buildPreshower();
00984       return false;
00985     }
00986   
00987   //  std::cout << *segiterator << std::endl;
00988   // get the position of the origin
00989   
00990   XYZPoint origin;
00991   if(inCm)
00992     {
00993       origin=segiterator->positionAtDepthincm(currentdepth_);
00994     }
00995   else
00996     {
00997       if(EMSHOWER)
00998         origin=segiterator->positionAtDepthinX0(currentdepth_);
00999       if(HADSHOWER)
01000         origin=segiterator->positionAtDepthinL0(currentdepth_);
01001     }
01002   //  std::cout << " currentdepth_ " << currentdepth_ << " " << origin << std::endl;
01003   XYZVector newaxis=pivot_.getFirstEdge().Cross(normal_);
01004 
01005 //  std::cout  << "Normal " << normal_ << std::endl;
01006 //  std::cout << " New axis " << newaxis << std::endl;
01007 
01008 //  std::cout << " ncrystals  " << ncrystals << std::endl;
01009   plan_ = Plane3D((Vector)normal_,(Point)origin);
01010 
01011   unsigned nquads=0;
01012   double sign=(central_) ? -1.: 1.;
01013   Transform3DR trans((Point)origin,(Point)(origin+normal_),(Point)(origin+newaxis),
01014                      Point(0,0,0), Point(0.,0.,sign),      Point(0.,1.,0.));
01015   for(unsigned ic=0;ic<ncrystals_;++ic)
01016     {
01017       //      std::cout << " Building geometry for " << regionOfInterest_[ic].getCellID() << std::endl;
01018       XYZPoint a,b;
01019 
01020       //      std::cout << " Origin " << origin << std::endl;
01021 
01022       //      std::vector<XYZPoint> corners;
01023       //      corners.reserve(4);
01024       double dummyt;
01025       bool hasbeenpulled=false;
01026       bool behindback=false;
01027       for(unsigned il=0;il<4;++il)
01028         {
01029           // a is the il-th front corner of the crystal. b is the corresponding rear corner
01030           regionOfInterest_[ic].getLateralEdges(il,a,b);
01031           
01032           // pull the surface if necessary (only in the front of the crystals) 
01033           XYZPoint aprime=a;
01034           if(pulled(origin,normal_,a)) 
01035             {
01036               b=aprime;
01037               hasbeenpulled=true;
01038             }
01039           
01040           // compute the intersection. 
01041           // Check that the intersection is in the [a,b] segment  if HADSHOWER
01042           // if EMSHOWER the intersection is calculated as if the crystals were infinite
01043           XYZPoint xx=(EMSHOWER)?intersect(plan_,a,b,dummyt,false):intersect(plan_,a,b,dummyt,true);
01044           
01045           if(dummyt>1) behindback=true;
01046           //      std::cout << " Intersect " << il << " " << a << " " << b << " " << plan_ << " " << xx << std::endl;
01047           // check that the intersection actually exists 
01048           if(xx.mag2()!=0)
01049             {
01050               corners[il] = xx;
01051             }     
01052         }    
01053       //      std::cout << " ncorners " << corners.size() << std::endl;
01054       if(behindback&&EMSHOWER) detailedShowerTail_=true;
01055       // If the quad is completly defined. Store it ! 
01056       if(corners.size()==4)
01057         {
01058           padsatdepth_[ic]=CrystalPad(ic,corners,trans,bfactor_,!central_);
01059           // Parameter to be tuned
01060           if(hasbeenpulled) padsatdepth_[ic].setSurvivalProbability(pulledPadProbability_);
01061           validPads_[ic]=true;
01062           ++nquads;     
01063           // In principle, this should be done after the quads reorganization. But it would cost one more loop
01064           //  quadsatdepth_[ic].extrems(locxmin,locxmax,locymin,locymax);
01065           //  if(locxmin<xmin_) xmin_=locxmin;
01066           //  if(locymin<ymin_) ymin_=locymin;
01067           //  if(locxmax>xmax_) xmax_=locxmax;
01068           //  if(locymax>ymax_) ymax_=locymax;
01069         }
01070       else
01071         {
01072           padsatdepth_[ic]=CrystalPad();
01073           validPads_[ic]=false;
01074         }
01075     }
01076   //  std::cout << " Number of quads " << quadsatdepth_.size() << std::endl; 
01077   if(doreorg_)reorganizePads();
01078   //  std::cout << "Finished to reorganize " << std::endl;
01079   npadsatdepth_=nquads;
01080   //  std::cout << " prepareCellIDMap " << std::endl;
01081   
01082 
01083   // Resize the Quads to allow for some numerical inaccuracy 
01084   // in the "inside" function
01085   for(unsigned ic=0;ic<ncrystals_;++ic) 
01086     {
01087     
01088       if (!validPads_[ic]) continue;
01089 
01090       if(EMSHOWER) padsatdepth_[ic].resetCorners();
01091 
01092       padsatdepth_[ic].extrems(locxmin,locxmax,locymin,locymax);
01093       if(locxmin<xmin_) xmin_=locxmin;
01094       if(locymin<ymin_) ymin_=locymin;
01095       if(locxmax>xmax_) xmax_=locxmax;
01096       if(locymax>ymax_) ymax_=locymax;
01097     }
01098   
01099   sizex_=(xmax_-xmin_)/nx_;
01100   sizey_=(ymax_-ymin_)/ny_;
01101 
01102 
01103   // Make sure that sizex_ and sizey_ are set before running prepareCellIDMap
01104   prepareCrystalNumberArray();
01105 
01106   //  std::cout << " Finished  prepareCellIDMap " << std::endl;
01107   ncrackpadsatdepth_=crackpadsatdepth_.size();
01108 
01109   return true;
01110 }
01111 
01112 
01113 
01114 
01115 void 
01116 EcalHitMaker::configureGeometry()
01117 { 
01118   configuredGeometry_=true;
01119   for(unsigned ic=0;ic<ncrystals_;++ic)
01120     {
01121       //      std::cout << " Building " << cellids_[ic] << std::endl;
01122       for(unsigned idir=0;idir<8;++idir)
01123         {
01124 
01125           unsigned oppdir=CaloDirectionOperations::oppositeDirection(idir);
01126           // Is there something else to do ? 
01127           // The relationship with the neighbour may have been set previously.
01128           if(regionOfInterest_[ic].crystalNeighbour(idir).status()>=0) 
01129             {
01130               //              std::cout << " Nothing to do " << std::endl;
01131               continue ;
01132             }
01133 
01134           const DetId & oldcell(regionOfInterest_[ic].getDetId());
01135           CaloDirection dir=CaloDirectionOperations::neighbourDirection(idir);
01136           DetId newcell(oldcell);
01137           if(!myCalorimeter->move(newcell,dir))
01138             {
01139               // no neighbour in this direction
01140               regionOfInterest_[ic].crystalNeighbour(idir).setStatus(-1);
01141               continue;
01142             }
01143           // Determine the number of this neighbour
01144           //      std::cout << " The neighbour is " << newcell << std::endl;
01145           std::map<DetId,unsigned>::const_iterator niter(DetIdMap_.find(newcell));
01146           if(niter==DetIdMap_.end())
01147             {
01148               //              std::cout << " The neighbour is not in the map " << std::endl;
01149               regionOfInterest_[ic].crystalNeighbour(idir).setStatus(-1);
01150               continue;
01151             }
01152           // Now there is a neighbour     
01153           //      std::cout << " The neighbour is " << niter->second << " " << cellids_[niter->second] << std::endl;
01154           regionOfInterest_[ic].crystalNeighbour(idir).setNumber(niter->second);
01155           //      std::cout << " Managed to set crystalNeighbour " << ic << " " << idir << std::endl;
01156           //      std::cout << " Trying  " << niter->second << " " << oppdir << std::endl;
01157           regionOfInterest_[niter->second].crystalNeighbour(oppdir).setNumber(ic);
01158           //      std::cout << " Crack/gap " << std::endl;
01159           if(myCalorimeter->borderCrossing(oldcell,newcell))
01160             {
01161               regionOfInterest_[ic].crystalNeighbour(idir).setStatus(1);
01162               regionOfInterest_[niter->second].crystalNeighbour(oppdir).setStatus(1);
01163               //              std::cout << " Crack ! " << std::endl;
01164             }
01165           else
01166             {
01167               regionOfInterest_[ic].crystalNeighbour(idir).setStatus(0);
01168               regionOfInterest_[niter->second].crystalNeighbour(oppdir).setStatus(0);
01169               //              std::cout << " Gap" << std::endl;
01170             }       
01171         }
01172     }
01173     // Magnetic field a la Charlot
01174   double theta=EcalEntrance_.theta();
01175   if(theta>M_PI_2) theta=M_PI-theta;
01176   bfactor_=1./(1.+0.133*theta);
01177   if(myCalorimeter->magneticField()==0. ) bfactor_=1.;
01178 }
01179 
01180 // project fPoint on the plane (original,normal)
01181 bool 
01182 EcalHitMaker::pulled(const XYZPoint & origin, 
01183                      const XYZNormal& normal, 
01184                      XYZPoint & fPoint) const 
01185 {
01186   // check if fPoint is behind the origin
01187   double dotproduct=normal.Dot(fPoint-origin);
01188   if(dotproduct<=0.) return false;
01189 
01190   //norm of normal is 1 
01191   fPoint -= (1+dotproduct)*normal;
01192   return true;
01193 }
01194 
01195 
01196 void 
01197 EcalHitMaker::prepareCrystalNumberArray()
01198 {
01199   for(unsigned iq=0;iq<npadsatdepth_;++iq)
01200     {
01201       if(!validPads_[iq]) continue;
01202       unsigned d1,d2;
01203       convertIntegerCoordinates(padsatdepth_[iq].center().x(),padsatdepth_[iq].center().y(),d1,d2);
01204       myCrystalNumberArray_[d1][d2]=iq;
01205     }
01206 }
01207 
01208 void EcalHitMaker::convertIntegerCoordinates(double x, double y,unsigned &ix,unsigned &iy) const 
01209 {
01210   int tix=(int)((x-xmin_)/sizex_);
01211   int tiy=(int)((y-ymin_)/sizey_);
01212   ix=iy=9999;
01213   if(tix>=0) ix=(unsigned)tix;
01214   if(tiy>=0) iy=(unsigned)tiy;
01215 }
01216 
01217 const std::map<CaloHitID,float>& EcalHitMaker::getHits() 
01218 {
01219   if (hitmaphasbeencalculated_) return hitMap_;
01220   for(unsigned ic=0;ic<ncrystals_;++ic)
01221     {
01222           //calculate time of flight
01223           float tof = 0.0;
01224           if(onEcal_==1 || onEcal_==2) tof = (myCalorimeter->getEcalGeometry(onEcal_)->getGeometry(regionOfInterest_[ic].getDetId())->getPosition().mag())/29.98; //speed of light
01225         
01226           if(onEcal_==1){
01227             CaloHitID current_id(EBDetId(regionOfInterest_[ic].getDetId().rawId()).hashedIndex(),tof,0); //no track yet
01228         hitMap_.insert(std::pair<CaloHitID,float>(current_id,hits_[ic]));
01229           }
01230           else if(onEcal_==2){
01231             CaloHitID current_id(EEDetId(regionOfInterest_[ic].getDetId().rawId()).hashedIndex(),tof,0); //no track yet
01232         hitMap_.insert(std::pair<CaloHitID,float>(current_id,hits_[ic]));
01233           }
01234     }
01235   hitmaphasbeencalculated_=true;
01236   return hitMap_;
01237 }
01238 
01239 
01241 
01242 void 
01243 EcalHitMaker::reorganizePads()
01244 {
01245 
01246   // Some cleaning first 
01247   //  std::cout << " Starting reorganize " << std::endl;
01248   crackpadsatdepth_.clear();
01249   crackpadsatdepth_.reserve(etasize_*phisize_);
01250   ncrackpadsatdepth_=0;
01251   std::vector<neighbour> gaps;
01252   std::vector<std::vector<neighbour> > cracks;  
01253   //  cracks.clear();
01254   cracks.resize(ncrystals_);
01255 
01256 
01257   for(unsigned iq=0;iq<ncrystals_;++iq)
01258     {
01259       if(!validPads_[iq]) continue;
01260 
01261       gaps.clear();
01262       //   std::cout << padsatdepth_[iq] << std::endl;
01263       //check all the directions
01264       for(unsigned iside=0;iside<4;++iside)
01265         {
01266           //      std::cout << " To be glued " << iside << " " << regionOfInterest_[iq].crystalNeighbour(iside).toBeGlued() << std::endl;
01267           CaloDirection thisside=CaloDirectionOperations::Side(iside);
01268           if(regionOfInterest_[iq].crystalNeighbour(iside).toBeGlued())
01269             {
01270               // look for the neighbour and check that it exists
01271               int neighbourstatus=regionOfInterest_[iq].crystalNeighbour(iside).status();
01272               if(neighbourstatus<0)
01273                 continue;
01274 
01275               unsigned neighbourNumber=regionOfInterest_[iq].crystalNeighbour(iside).number();
01276               if(!validPads_[neighbourNumber]) continue;
01277               // there is a crack between 
01278               if(neighbourstatus==1)
01279                 {
01280                   //              std::cout << " 1 Crack : " << thisside << " " << cellids_[iq]<< " " << cellids_[neighbourNumber] << std::endl;
01281                   cracks[iq].push_back(neighbour(thisside,neighbourNumber));
01282                 } // else it is a gap 
01283               else
01284                 {
01285                   gaps.push_back(neighbour(thisside,neighbourNumber));
01286                 }
01287             }
01288         }
01289       // Now lift the gaps
01290       gapsLifting(gaps,iq);
01291     }
01292 
01293   unsigned ncracks=cracks.size();
01294   //  std::cout << " Cracks treatment : " << cracks.size() << std::endl;
01295   for(unsigned icrack=0;icrack<ncracks;++icrack)
01296     {
01297       //      std::cout << " Crack number " << crackiter->first << std::endl;
01298       cracksPads(cracks[icrack],icrack);
01299     }
01300 
01301 }
01302 
01303 //dir 2 = N,E,W,S
01304 CLHEP::Hep2Vector & 
01305 EcalHitMaker::correspondingEdge(neighbour& myneighbour,CaloDirection dir2 ) 
01306 {
01307   CaloDirection dir=CaloDirectionOperations::oppositeSide(myneighbour.first);
01308   CaloDirection corner=CaloDirectionOperations::add2d(dir,dir2);
01309   //  std::cout << "Corresponding Edge " << dir<< " " << dir2 << " " << corner << std::endl;
01310   return padsatdepth_[myneighbour.second].edge(corner);  
01311 }
01312 
01313 bool EcalHitMaker::diagonalEdge(unsigned myPad, CaloDirection dir,CLHEP::Hep2Vector & point)
01314 {
01315   unsigned idir=CaloDirectionOperations::neighbourDirection(dir);
01316   if(regionOfInterest_[myPad].crystalNeighbour(idir).status()<0)
01317     return false;
01318   unsigned nneighbour=regionOfInterest_[myPad].crystalNeighbour(idir).number();
01319   if(!validPads_[nneighbour])
01320     {
01321       //      std::cout << " Wasn't able to move " << std::endl;
01322       return false;
01323     }
01324   point = padsatdepth_[nneighbour].edge(CaloDirectionOperations::oppositeSide(dir));
01325   return true;
01326 }
01327 
01328 bool EcalHitMaker::unbalancedDirection(const std::vector<neighbour>& dirs,unsigned & unb,unsigned & dir1, unsigned & dir2)
01329 {
01330   if(dirs.size()==1) return false;
01331   if(dirs.size()%2==0) return false;
01332   CaloDirection tmp;
01333   tmp=CaloDirectionOperations::add2d(dirs[0].first,dirs[1].first);
01334   if(tmp==NONE) 
01335     {
01336       unb=2;
01337       dir1=0;
01338       dir2=1;
01339       return true;
01340     }
01341   tmp=CaloDirectionOperations::add2d(dirs[0].first,dirs[2].first);
01342   if(tmp==NONE)
01343     { 
01344       unb=1;
01345       dir1=0;
01346       dir2=2;
01347       return true;
01348     }
01349   unb=0;
01350   dir1=1;
01351   dir2=2;
01352   return true;
01353 }
01354 
01355 
01356 void 
01357 EcalHitMaker::gapsLifting(std::vector<neighbour>& gaps,unsigned iq)
01358 {
01359   //  std::cout << " Entering gapsLifting "  << std::endl;
01360   CrystalPad & myPad = padsatdepth_[iq];
01361   unsigned ngaps=gaps.size();
01362   static bool debug=false;
01363   if(ngaps==1)
01364     {
01365       if(debug)
01366         {
01367           std::cout << " Avant " << ngaps << " " <<gaps[0].first<< std::endl;
01368           std::cout << myPad << std::endl;
01369         }
01370       if(gaps[0].first==NORTH||gaps[0].first==SOUTH)
01371         {
01372           CaloDirection dir1=CaloDirectionOperations::add2d(gaps[0].first,EAST);
01373           CaloDirection dir2=CaloDirectionOperations::add2d(gaps[0].first,WEST);
01374           myPad.edge(dir1)=correspondingEdge(gaps[0],EAST);
01375           myPad.edge(dir2)=correspondingEdge(gaps[0],WEST);
01376         }
01377       else
01378         {
01379           CaloDirection dir1=CaloDirectionOperations::add2d(gaps[0].first,NORTH);
01380           CaloDirection dir2=CaloDirectionOperations::add2d(gaps[0].first,SOUTH);
01381           myPad.edge(dir1)=correspondingEdge(gaps[0],NORTH);
01382           myPad.edge(dir2)=correspondingEdge(gaps[0],SOUTH);
01383         }
01384       if(debug)
01385         {
01386           std::cout << " Apres " << std::endl;
01387           std::cout << myPad << std::endl;
01388         }
01389     }
01390   else
01391     if(ngaps==2)
01392       {
01393         if(debug)
01394           {
01395             std::cout << " Avant " << ngaps << " " <<gaps[0].first<< " " <<gaps[1].first << std::endl;
01396             std::cout << myPad << std::endl;
01397             std::cout << " Voisin 1 " << (gaps[0].second) << std::endl;
01398             std::cout << " Voisin 2 " << (gaps[1].second) << std::endl;
01399           }
01400         CaloDirection corner0=CaloDirectionOperations::add2d(gaps[0].first,gaps[1].first);
01401 
01402         CLHEP::Hep2Vector point(0.,0.);
01403         if(corner0!=NONE&&diagonalEdge(iq,corner0,point))
01404           {
01405             CaloDirection corner1=CaloDirectionOperations::add2d(CaloDirectionOperations::oppositeSide(gaps[0].first),gaps[1].first);
01406             CaloDirection corner2=CaloDirectionOperations::add2d(gaps[0].first,CaloDirectionOperations::oppositeSide(gaps[1].first));
01407             myPad.edge(corner0) = point;
01408             myPad.edge(corner1) = correspondingEdge(gaps[1],CaloDirectionOperations::oppositeSide(gaps[0].first));
01409             myPad.edge(corner2) = correspondingEdge(gaps[0],CaloDirectionOperations::oppositeSide(gaps[1].first));
01410           }
01411         else
01412           if(corner0==NONE)
01413             {
01414               if(gaps[0].first==EAST||gaps[0].first==WEST)
01415                 {
01416                   CaloDirection corner1=CaloDirectionOperations::add2d(gaps[0].first,NORTH);
01417                   CaloDirection corner2=CaloDirectionOperations::add2d(gaps[0].first,SOUTH);
01418                   myPad.edge(corner1)=correspondingEdge(gaps[0],NORTH);
01419                   myPad.edge(corner2)=correspondingEdge(gaps[0],SOUTH);
01420                   
01421                   corner1=CaloDirectionOperations::add2d(gaps[1].first,NORTH);
01422                   corner2=CaloDirectionOperations::add2d(gaps[1].first,SOUTH);
01423                   myPad.edge(corner1)=correspondingEdge(gaps[1],NORTH);
01424                   myPad.edge(corner2)=correspondingEdge(gaps[1],SOUTH);
01425                 }
01426               else
01427                 {
01428                   CaloDirection corner1=CaloDirectionOperations::add2d(gaps[0].first,EAST);
01429                   CaloDirection corner2=CaloDirectionOperations::add2d(gaps[0].first,WEST);
01430                   myPad.edge(corner1)=correspondingEdge(gaps[0],EAST);
01431                   myPad.edge(corner2)=correspondingEdge(gaps[0],WEST);
01432                   
01433                   corner1=CaloDirectionOperations::add2d(gaps[1].first,EAST);
01434                   corner2=CaloDirectionOperations::add2d(gaps[1].first,WEST);
01435                   myPad.edge(corner1)=correspondingEdge(gaps[1],EAST);
01436                   myPad.edge(corner2)=correspondingEdge(gaps[1],WEST);
01437                 }
01438             }
01439         if(debug)
01440           {
01441             std::cout << " Apres " << std::endl;
01442             std::cout << myPad << std::endl;
01443           }
01444       }
01445     else
01446       if(ngaps==3)
01447         {
01448           // in this case the four corners have to be changed 
01449           unsigned iubd,idir1,idir2;
01450           CaloDirection diag;
01451           CLHEP::Hep2Vector point(0.,0.);
01452           //      std::cout << " Yes : 3 gaps" << std::endl;
01453           if(unbalancedDirection(gaps,iubd,idir1,idir2))                
01454             {
01455               CaloDirection ubd(gaps[iubd].first),dir1(gaps[idir1].first);
01456               CaloDirection dir2(gaps[idir2].first);
01457               
01458               //              std::cout << " Avant " << std::endl << myPad << std::endl;
01459               //              std::cout << ubd << " " << dir1 << " " << dir2 << std::endl;
01460               diag=CaloDirectionOperations::add2d(ubd,dir1);
01461               if(diagonalEdge(iq,diag,point))
01462                 myPad.edge(diag)=point;
01463               diag=CaloDirectionOperations::add2d(ubd,dir2);
01464               if(diagonalEdge(iq,diag,point))
01465                 myPad.edge(diag)=point;
01466               CaloDirection oppside=CaloDirectionOperations::oppositeSide(ubd);
01467               myPad.edge(CaloDirectionOperations::add2d(oppside,dir1))=correspondingEdge(gaps[idir1],oppside);
01468               myPad.edge(CaloDirectionOperations::add2d(oppside,dir2))=correspondingEdge(gaps[idir2],oppside);
01469               //              std::cout << " Apres " << std::endl << myPad << std::endl;
01470             }                         
01471         }
01472       else
01473         if(ngaps==4)
01474           {
01475             //      std::cout << " Waouh :4 gaps" << std::endl;
01476             //      std::cout << " Avant " << std::endl;
01477             //      std::cout << myPad<< std::endl;
01478             CLHEP::Hep2Vector point(0.,0.);
01479             if(diagonalEdge(iq,NORTHEAST,point)) 
01480               myPad.edge(NORTHEAST)=point;
01481             if(diagonalEdge(iq,NORTHWEST,point)) 
01482               myPad.edge(NORTHWEST)=point;
01483             if(diagonalEdge(iq,SOUTHWEST,point)) 
01484               myPad.edge(SOUTHWEST)=point;
01485             if(diagonalEdge(iq,SOUTHEAST,point)) 
01486               myPad.edge(SOUTHEAST)=point;      
01487             //      std::cout << " Apres " << std::endl;
01488             //      std::cout << myPad<< std::endl;
01489           }   
01490 }
01491 
01492 void 
01493 EcalHitMaker::cracksPads(std::vector<neighbour> & cracks, unsigned iq)
01494 {
01495   //  std::cout << " myPad " << &myPad << std::endl;
01496   unsigned ncracks=cracks.size();
01497   CrystalPad & myPad = padsatdepth_[iq];
01498   for(unsigned ic=0;ic<ncracks;++ic)
01499     {
01500       //      std::vector<CLHEP::Hep2Vector> mycorners;
01501       //      mycorners.reserve(4);
01502       switch(cracks[ic].first)
01503         {
01504         case NORTH:
01505           {
01506             mycorners[0] = (padsatdepth_[cracks[ic].second].edge(SOUTHWEST));
01507             mycorners[1] = (padsatdepth_[cracks[ic].second].edge(SOUTHEAST));
01508             mycorners[2] = (myPad.edge(NORTHEAST));
01509             mycorners[3] = (myPad.edge(NORTHWEST));
01510           }
01511           break;
01512         case SOUTH:
01513           {
01514             mycorners[0] = (myPad.edge(SOUTHWEST));
01515             mycorners[1] = (myPad.edge(SOUTHEAST));
01516             mycorners[2] = (padsatdepth_[cracks[ic].second].edge(NORTHEAST));
01517             mycorners[3] = (padsatdepth_[cracks[ic].second].edge(NORTHWEST));
01518           }
01519           break;
01520         case EAST:
01521           {
01522             mycorners[0] = (myPad.edge(NORTHEAST));
01523             mycorners[1] = (padsatdepth_[cracks[ic].second].edge(NORTHWEST));
01524             mycorners[2] = (padsatdepth_[cracks[ic].second].edge(SOUTHWEST));
01525             mycorners[3] = (myPad.edge(SOUTHEAST));
01526           }
01527           break;
01528         case WEST:
01529           {
01530             mycorners[0] = (padsatdepth_[cracks[ic].second].edge(NORTHEAST));
01531             mycorners[1] = (myPad.edge(NORTHWEST));
01532             mycorners[2] = (myPad.edge(SOUTHWEST));
01533             mycorners[3] = (padsatdepth_[cracks[ic].second].edge(SOUTHEAST));
01534           }
01535           break;
01536         default:
01537           {
01538           }
01539         }  
01540       CrystalPad crackpad(ic,mycorners);
01541       // to be tuned. A simpleconfigurable should be used
01542       crackpad.setSurvivalProbability(crackPadProbability_);   
01543       crackpadsatdepth_.push_back(crackpad);
01544     }
01545   //  std::cout << " Finished cracksPads " << std::endl;
01546 }
01547 
01548 
01549 bool EcalHitMaker::inside3D(const std::vector<XYZPoint>& corners, 
01550                             const XYZPoint& p) const
01551 {
01552   // corners and p are in the same plane
01553   // p is inside "corners" if the four crossproducts (corners[i]xcorners[i+1]) 
01554   // are in the same direction
01555 
01556   XYZVector crossproduct(0.,0.,0.),previouscrossproduct(0.,0.,0.);
01557 
01558   for(unsigned ip=0;ip<4 ; ++ip) {
01559     crossproduct = (corners[ip]-p).Cross(corners[(ip+1)%4]-p);
01560     if(ip==0)
01561         previouscrossproduct=crossproduct;
01562     else
01563       if (crossproduct.Dot(previouscrossproduct)<0.) return false;       
01564   }
01565 
01566   return true;
01567 }