CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/Alignment/LaserAlignment/plugins/TkLasBeamFitter.cc

Go to the documentation of this file.
00001 
00017 // framework include files
00018 #include "FWCore/Framework/interface/Frameworkfwd.h"
00019 #include "FWCore/Framework/interface/one/EDProducer.h"
00020 #include "FWCore/Framework/interface/ESHandle.h"
00021 #include "FWCore/Framework/interface/Event.h"
00022 #include "FWCore/Framework/interface/EventSetup.h"
00023 #include "FWCore/Framework/interface/MakerMacros.h"
00024 #include "FWCore/Framework/interface/Run.h"
00025 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00026 #include "FWCore/Utilities/interface/InputTag.h"
00027 #include "FWCore/ServiceRegistry/interface/Service.h"
00028 #include "CommonTools/UtilAlgos/interface/TFileService.h"
00029 
00030 #include <Geometry/CommonDetUnit/interface/GeomDetUnit.h>
00031 #include <Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h>
00032 #include <Geometry/Records/interface/TrackerDigiGeometryRecord.h>
00033 #include <MagneticField/Engine/interface/MagneticField.h>
00034 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
00035 
00036 // data formats
00037 // for edm::InRun
00038 #include "DataFormats/Provenance/interface/BranchType.h"
00039 
00040 // laser data formats
00041 #include "DataFormats/Alignment/interface/TkLasBeam.h"
00042 #include "DataFormats/Alignment/interface/TkFittedLasBeam.h"
00043 
00044 // further includes
00045 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateOnSurface.h"
00046 #include "Alignment/LaserAlignment/interface/TsosVectorCollection.h"
00047 #include "TrackingTools/TrajectoryState/interface/FreeTrajectoryState.h"
00048 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
00049 
00050 #include <iostream>
00051 #include "TMinuit.h"
00052 #include "TGraphErrors.h"
00053 #include "TF1.h"
00054 #include "TH1.h"
00055 #include "TH2.h"
00056 
00057 using namespace edm;
00058 using namespace std;
00059 
00060 
00061 //
00062 // class declaration
00063 //
00064 
00065 class TkLasBeamFitter : public edm::one::EDProducer<edm::EndRunProducer> {
00066 public:
00067   explicit TkLasBeamFitter(const edm::ParameterSet &config);
00068   ~TkLasBeamFitter();
00069   
00070   //virtual void beginJob(const edm::EventSetup& /*access deprecated*/) {}
00071   virtual void produce(edm::Event &event, const edm::EventSetup &setup) override;
00072   // virtual void beginRun(edm::Run &run, const edm::EventSetup &setup);
00073   virtual void endRunProduce(edm::Run &run, const edm::EventSetup &setup) override;
00074   //virtual void endJob() {}
00075 
00076 private:
00079   void getLasBeams(TkFittedLasBeam &beam,vector<TrajectoryStateOnSurface> &tsosLas);
00080   void getLasHits(TkFittedLasBeam &beam, const SiStripLaserRecHit2D &hit, 
00081                   vector<const GeomDetUnit*> &gd, vector<GlobalPoint> &globHit,
00082                   unsigned int &hitsAtTecPlus); 
00083 //   void fillVectors(TkFittedLasBeam &beam);
00084 
00085   // need static functions to be used in fitter(..);
00086   // all parameters used therein have to be static, as well (see below)
00087   static double tecPlusFunction(double *x, double *par);
00088   static double tecMinusFunction(double *x, double *par);
00089   static double atFunction(double *x, double *par);
00090 
00091   void fitter(TkFittedLasBeam &beam, AlgebraicSymMatrix &covMatrix, 
00092               unsigned int &hitsAtTecPlus, unsigned int &nFitParams,
00093               std::vector<double> &hitPhi, std::vector<double> &hitPhiError, std::vector<double> &hitZprimeError,
00094               double &zMin, double &zMax, double &bsAngleParam,
00095               double &offset, double &offsetError, double &slope, double &slopeError,
00096               double &phiAtMinusParam, double &phiAtPlusParam,
00097               double &atThetaSplitParam);
00098 
00099   void trackPhi(TkFittedLasBeam &beam, unsigned int &hit,
00100                 double &trackPhi, double &trackPhiRef,
00101                 double &offset, double &slope, double &bsAngleParam, 
00102                 double &phiAtMinusParam, double &phiAtPlusParam,
00103                 double &atThetaSplitParam, std::vector<GlobalPoint> &globHit);
00104 
00105   void globalTrackPoint(TkFittedLasBeam &beam, 
00106                         unsigned int &hit, unsigned int &hitsAtTecPlus,
00107                         double &trackPhi, double &trackPhiRef, 
00108                         std::vector<GlobalPoint> &globHit, std::vector<GlobalPoint> &globPtrack,
00109                         GlobalPoint &globPref, std::vector<double> &hitPhiError);
00110 
00111   void buildTrajectory(TkFittedLasBeam &beam, unsigned int &hit,
00112                        vector<const GeomDetUnit*> &gd, std::vector<GlobalPoint> &globPtrack,
00113                        vector<TrajectoryStateOnSurface> &tsosLas, GlobalPoint &globPref);
00114 
00115   bool fitBeam(TkFittedLasBeam &beam, AlgebraicSymMatrix &covMatrix, 
00116                unsigned int &hitsAtTecPlus, unsigned int &nFitParams,
00117                double &offset, double &slope, vector<GlobalPoint> &globPtrack, 
00118                double &bsAngleParam, double &chi2);
00119 
00120   // ----------member data ---------------------------
00121   const edm::InputTag src_;
00122   bool fitBeamSplitters_;
00123   unsigned int nAtParameters_;
00124 
00125   edm::Service<TFileService> fs;
00126 
00127   // static parameters used in static parametrization functions
00128   static vector<double> gHitZprime;
00129   static vector<double> gBarrelModuleRadius;
00130   static vector<double> gBarrelModuleOffset;
00131   static float gTIBparam;
00132   static float gTOBparam;
00133   static double gBeamR;
00134   static double gBeamZ0;
00135   static double gBeamSplitterZprime;
00136   static unsigned int gHitsAtTecMinus;
00137   static double gBSparam;
00138   static bool gFitBeamSplitters;
00139   static bool gIsInnerBarrel;
00140 
00141   // histograms
00142   TH1F *h_bsAngle, *h_hitX, *h_hitXTecPlus, *h_hitXTecMinus,
00143     *h_hitXAt, *h_chi2, *h_chi2ndof, *h_pull, *h_res, 
00144     *h_resTecPlus, *h_resTecMinus, *h_resAt;
00145   TH2F *h_bsAngleVsBeam, *h_hitXvsZTecPlus, *h_hitXvsZTecMinus,
00146     *h_hitXvsZAt, *h_resVsZTecPlus, *h_resVsZTecMinus, *h_resVsZAt,
00147     *h_resVsHitTecPlus, *h_resVsHitTecMinus, *h_resVsHitAt;
00148 }; 
00149 
00150 //
00151 // constants, enums and typedefs
00152 //
00153 
00154 
00155 //
00156 // static data member definitions
00157 //
00158 
00159 // static parameters used in parametrization functions
00160 vector<double> TkLasBeamFitter::gHitZprime;
00161 vector<double> TkLasBeamFitter::gBarrelModuleRadius;
00162 vector<double> TkLasBeamFitter::gBarrelModuleOffset;
00163 float TkLasBeamFitter::gTIBparam = 0.097614; // = abs(r_offset/r_module) (nominal!)
00164 float TkLasBeamFitter::gTOBparam = 0.034949; // = abs(r_offset/r_module) (nominal!)
00165 double TkLasBeamFitter::gBeamR = 0.0;
00166 double TkLasBeamFitter::gBeamZ0 = 0.0; 
00167 double TkLasBeamFitter::gBeamSplitterZprime = 0.0;
00168 unsigned int TkLasBeamFitter::gHitsAtTecMinus = 0;
00169 double TkLasBeamFitter::gBSparam = 0.0;
00170 bool TkLasBeamFitter::gFitBeamSplitters = 0;
00171 bool TkLasBeamFitter::gIsInnerBarrel = 0;
00172 
00173 // handles
00174 Handle<TkLasBeamCollection> laserBeams;
00175 ESHandle<MagneticField> fieldHandle;
00176 ESHandle<TrackerGeometry> geometry;
00177 
00178 //
00179 // constructors and destructor
00180 //
00181 TkLasBeamFitter::TkLasBeamFitter(const edm::ParameterSet &iConfig) :
00182   src_(iConfig.getParameter<edm::InputTag>("src")),
00183   fitBeamSplitters_(iConfig.getParameter<bool>("fitBeamSplitters")),
00184   nAtParameters_(iConfig.getParameter<unsigned int>("numberOfFittedAtParameters")),
00185   h_bsAngle(0), h_hitX(0), h_hitXTecPlus(0), h_hitXTecMinus(0),
00186   h_hitXAt(0), h_chi2(0), h_chi2ndof(0), h_pull(0), h_res(0), 
00187   h_resTecPlus(0), h_resTecMinus(0), h_resAt(0),
00188   h_bsAngleVsBeam(0), h_hitXvsZTecPlus(0), h_hitXvsZTecMinus(0),
00189   h_hitXvsZAt(0), h_resVsZTecPlus(0), h_resVsZTecMinus(0), h_resVsZAt(0),
00190   h_resVsHitTecPlus(0), h_resVsHitTecMinus(0), h_resVsHitAt(0)
00191 {
00192   // declare the products to produce
00193   this->produces<TkFittedLasBeamCollection, edm::InRun>();
00194   this->produces<TsosVectorCollection, edm::InRun>();
00195   
00196   //now do what ever other initialization is needed
00197 }
00198 
00199 //---------------------------------------------------------------------------------------
00200 TkLasBeamFitter::~TkLasBeamFitter()
00201 {
00202  
00203    // do anything here that needs to be done at desctruction time
00204    // (e.g. close files, deallocate resources etc.)
00205 
00206 }
00207 
00208 
00209 //
00210 // member functions
00211 //
00212 
00213 //---------------------------------------------------------------------------------------
00214 // ------------ method called to produce the data  ------------
00215 void TkLasBeamFitter::produce(edm::Event &iEvent, const edm::EventSetup &setup)
00216 {
00217   // Nothing per event!
00218 }
00219 
00220 //---------------------------------------------------------------------------------------
00221 // ------------ method called at end of each run  ---------------------------------------
00222 void TkLasBeamFitter::endRunProduce(edm::Run &run, const edm::EventSetup &setup)
00223 {
00224 // }
00225 // // FIXME!
00226 // // Indeed, that should be in endRun(..) - as soon as AlignmentProducer can call
00227 // // the algorithm's endRun correctly!
00228 //
00229 //
00230 // void TkLasBeamFitter::beginRun(edm::Run &run, const edm::EventSetup &setup)
00231 // {
00232 
00233   // book histograms
00234   h_hitX = fs->make<TH1F>("hitX","local x of LAS hits;local x [cm];N",100,-0.5,0.5);
00235   h_hitXTecPlus = fs->make<TH1F>("hitXTecPlus","local x of LAS hits in TECplus;local x [cm];N",100,-0.5,0.5);
00236   h_hitXTecMinus = fs->make<TH1F>("hitXTecMinus","local x of LAS hits in TECminus;local x [cm];N",100,-0.5,0.5);
00237   h_hitXAt = fs->make<TH1F>("hitXAt","local x of LAS hits in ATs;local x [cm];N",100,-2.5,2.5);
00238   h_hitXvsZTecPlus = fs->make<TH2F>("hitXvsZTecPlus","local x vs z in TECplus;z [cm];local x [cm]",80,120,280,100,-0.5,0.5);
00239   h_hitXvsZTecMinus = fs->make<TH2F>("hitXvsZTecMinus","local x vs z in TECMinus;z [cm];local x [cm]",80,-280,-120,100,-0.5,0.5);
00240   h_hitXvsZAt = fs->make<TH2F>("hitXvsZAt","local x vs z in ATs;z [cm];local x [cm]",200,-200,200,100,-0.5,0.5);
00241   h_chi2 = fs->make<TH1F>("chi2","#chi^{2};#chi^{2};N",100,0,2000);
00242   h_chi2ndof = fs->make<TH1F>("chi2ndof","#chi^{2} per degree of freedom;#chi^{2}/N_{dof};N",100,0,300);
00243   h_pull = fs->make<TH1F>("pull","pulls of #phi residuals;pull;N",50,-10,10);
00244   h_res = fs->make<TH1F>("res","#phi residuals;#phi_{track} - #phi_{hit} [rad];N",60,-0.0015,0.0015);
00245   h_resTecPlus = fs->make<TH1F>("resTecPlus","#phi residuals in TECplus;#phi_{track} - #phi_{hit} [rad];N",30,-0.0015,0.0015);
00246   h_resTecMinus = fs->make<TH1F>("resTecMinus","#phi residuals in TECminus;#phi_{track} - #phi_{hit} [rad];N",60,-0.0015,0.0015);
00247   h_resAt = fs->make<TH1F>("resAt","#phi residuals in ATs;#phi_{track} - #phi_{hit} [rad];N",30,-0.0015,0.0015);
00248   h_resVsZTecPlus = fs->make<TH2F>("resVsZTecPlus","phi residuals vs. z in TECplus;z [cm];#phi_{track} - #phi_{hit} [rad]",
00249                          80,120,280,100,-0.0015,0.0015);
00250   h_resVsZTecMinus = fs->make<TH2F>("resVsZTecMinus","phi residuals vs. z in TECminus;z [cm];#phi_{track} - #phi_{hit} [rad]",
00251                           80,-280,-120,100,-0.0015,0.0015);
00252   h_resVsZAt = fs->make<TH2F>("resVsZAt","#phi residuals vs. z in ATs;N;#phi_{track} - #phi_{hit} [rad]",
00253                     200,-200,200,100,-0.0015,0.0015);
00254   h_resVsHitTecPlus = fs->make<TH2F>("resVsHitTecPlus","#phi residuals vs. hits in TECplus;hit no.;#phi_{track} - #phi_{hit} [rad]",
00255                            144,0,144,100,-0.0015,0.0015);
00256   h_resVsHitTecMinus = fs->make<TH2F>("resVsHitTecMinus","#phi residuals vs. hits in TECminus;hit no.;#phi_{track} - #phi_{hit} [rad]",
00257                             144,0,144,100,-0.0015,0.0015);
00258   h_resVsHitAt = fs->make<TH2F>("resVsHitAt","#phi residuals vs. hits in ATs;hit no.;#phi_{track} - #phi_{hit} [rad]",
00259                       176,0,176,100,-0.0015,0.0015);
00260   h_bsAngle = fs->make<TH1F>("bsAngle","fitted beam splitter angle;BS angle [rad];N",40,-0.004,0.004);
00261   h_bsAngleVsBeam = fs->make<TH2F>("bsAngleVsBeam","fitted beam splitter angle per beam;Beam no.;BS angle [rad]",
00262                          40,0,300,100,-0.004,0.004);
00263 
00264   // Create output collections - they are parallel.
00265   // (edm::Ref etc. and thus edm::AssociationVector are not supported for edm::Run...)
00266   std::auto_ptr<TkFittedLasBeamCollection> fittedBeams(new TkFittedLasBeamCollection);
00267   // One std::vector<TSOS> for each TkFittedLasBeam:
00268   std::auto_ptr<TsosVectorCollection> tsosesVec(new TsosVectorCollection);
00269 
00270   // get TkLasBeams, Tracker geometry, magnetic field
00271   run.getByLabel( "LaserAlignment", "tkLaserBeams", laserBeams );
00272   setup.get<TrackerDigiGeometryRecord>().get(geometry);
00273   setup.get<IdealMagneticFieldRecord>().get(fieldHandle);
00274 
00275   // hack for fixed BSparams (ugly!)
00276 //   double bsParams[34] = {-0.000266,-0.000956,-0.001205,-0.000018,-0.000759,0.002554,
00277 //                       0.000465,0.000975,0.001006,0.002027,-0.001263,-0.000763,
00278 //                       -0.001702,0.000906,-0.002120,0.001594,0.000661,-0.000457,
00279 //                       -0.000447,0.000347,-0.002266,-0.000446,0.000659,0.000018,
00280 //                       -0.001630,-0.000324,
00281 //                       // ATs
00282 //                       -999.,-0.001709,-0.002091,-999.,
00283 //                       -0.001640,-999.,-0.002444,-0.002345};
00284 
00285   double bsParams[40] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00286                          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00287 
00288   // beam counter
00289   unsigned int beamNo(0);
00290   // fit BS? If false, values from bsParams are taken
00291   gFitBeamSplitters = fitBeamSplitters_;
00292   if(fitBeamSplitters_) cout << "Fitting BS!" << endl;
00293   else cout << "BS fixed, not fitted!" << endl;
00294 
00295   // loop over LAS beams
00296   for(TkLasBeamCollection::const_iterator iBeam = laserBeams->begin(), iEnd = laserBeams->end();
00297        iBeam != iEnd; ++iBeam){
00298 
00299     TkFittedLasBeam beam(*iBeam);
00300     vector<TrajectoryStateOnSurface> tsosLas;
00301 
00302     // set BS param for fit
00303     gBSparam = bsParams[beamNo];
00304 
00305     // call main function; all other functions are called inside getLasBeams(..)
00306     this->getLasBeams(beam, tsosLas);
00307     
00308     // fill output products
00309     fittedBeams->push_back(beam);
00310     tsosesVec->push_back(tsosLas);
00311 
00312 //     if(!this->fitBeam(fittedBeams->back(), tsosesVec->back())){
00313 //       edm::LogError("BadFit") 
00314 //       << "Problems fitting TkLasBeam, id " << fittedBeams->back().getBeamId() << ".";
00315 //       fittedBeams->pop_back(); // remove last entry added just before
00316 //       tsosesVec->pop_back();   // dito
00317 //     }
00318 
00319     beamNo++;
00320   }
00321   
00322   // finally, put fitted beams and TSOS vectors into run
00323   run.put(fittedBeams);
00324   run.put(tsosesVec);
00325 }
00326 
00327 // methods for las data processing
00328 
00329 // -------------- loop over beams, call functions ----------------------------
00330 void TkLasBeamFitter::getLasBeams(TkFittedLasBeam &beam, vector<TrajectoryStateOnSurface> &tsosLas)
00331 {
00332   cout << "---------------------------------------" << endl;
00333   cout << "beam id: " << beam.getBeamId() // << " isTec: " << (beam.isTecInternal() ? "Y" : "N") 
00334        << " isTec+: " << (beam.isTecInternal(1) ? "Y" : "N") << " isTec-: " << (beam.isTecInternal(-1) ? "Y" : "N")
00335        << " isAt: " << (beam.isAlignmentTube() ? "Y" : "N") << " isR6: " << (beam.isRing6() ? "Y" : "N")
00336        << endl;
00337  
00338   // reset static variables 
00339   gHitsAtTecMinus = 0;
00340   gHitZprime.clear();
00341   gBarrelModuleRadius.clear();
00342   gBarrelModuleOffset.clear();
00343 
00344   // set right beam radius
00345   gBeamR = beam.isRing6() ? 84.0 : 56.4;
00346   
00347   vector<const GeomDetUnit*> gd;
00348   vector<GlobalPoint> globHit;
00349   unsigned int hitsAtTecPlus(0);
00350   double sumZ(0.);
00351 
00352   // loop over hits
00353   for( TkLasBeam::const_iterator iHit = beam.begin(); iHit < beam.end(); ++iHit ){
00354     // iHit is a SiStripLaserRecHit2D
00355 
00356     const SiStripLaserRecHit2D hit(*iHit);
00357 
00358     this->getLasHits(beam, hit, gd, globHit, hitsAtTecPlus);
00359     sumZ += globHit.back().z();
00360 
00361     // fill histos
00362     h_hitX->Fill(hit.localPosition().x());
00363     // TECplus
00364     if(beam.isTecInternal(1)){
00365       h_hitXTecPlus->Fill(hit.localPosition().x());
00366       h_hitXvsZTecPlus->Fill(globHit.back().z(),hit.localPosition().x());
00367     }
00368     // TECminus
00369     else if(beam.isTecInternal(-1)){
00370       h_hitXTecMinus->Fill(hit.localPosition().x());
00371       h_hitXvsZTecMinus->Fill(globHit.back().z(),hit.localPosition().x());
00372     }
00373     // ATs
00374     else{
00375       h_hitXAt->Fill(hit.localPosition().x());
00376       h_hitXvsZAt->Fill(globHit.back().z(),hit.localPosition().x());
00377     }  
00378   }
00379 
00380   gBeamZ0 = sumZ / globHit.size();
00381   double zMin(0.), zMax(0.);
00382   // TECplus
00383   if(beam.isTecInternal(1)){
00384     gBeamSplitterZprime = 205.75 - gBeamZ0;
00385     zMin = 120.0 - gBeamZ0;
00386     zMax = 280.0 - gBeamZ0;
00387   }
00388   // TECminus
00389   else if(beam.isTecInternal(-1)){
00390     gBeamSplitterZprime = -205.75 - gBeamZ0;
00391     zMin = -280.0 - gBeamZ0;
00392     zMax = -120.0 - gBeamZ0;
00393   }
00394   // AT
00395   else{
00396     gBeamSplitterZprime = 112.3 - gBeamZ0;
00397     zMin = -200.0 - gBeamZ0;
00398     zMax = 200.0 - gBeamZ0;
00399   }
00400 
00401   // fill vectors for fitted quantities
00402   vector<double> hitPhi, hitPhiError, hitZprimeError;
00403 
00404   for(unsigned int hit = 0; hit < globHit.size(); ++hit){
00405     hitPhi.push_back(static_cast<double>(globHit[hit].phi()));
00406     // localPositionError[hit] or assume 0.003, 0.006
00407     hitPhiError.push_back( 0.003 / globHit[hit].perp());
00408     // no errors on z, fill with zeros
00409     hitZprimeError.push_back(0.0);
00410     // barrel-specific values
00411     if(beam.isAlignmentTube() && abs(globHit[hit].z()) < 112.3){
00412       gBarrelModuleRadius.push_back(globHit[hit].perp());
00413       gBarrelModuleOffset.push_back(gBarrelModuleRadius.back() - gBeamR);
00414       // TIB/TOB flag
00415       if(gBarrelModuleOffset.back() < 0.0){
00416         gIsInnerBarrel = 1;
00417       }
00418       else{
00419         gIsInnerBarrel = 0;
00420       }
00421       gHitZprime.push_back(globHit[hit].z() - gBeamZ0 - abs(gBarrelModuleOffset.back())); 
00422     }
00423     // non-barrel z'
00424     else{
00425       gHitZprime.push_back(globHit[hit].z() - gBeamZ0);
00426     }
00427   }
00428 
00429   // number of fit parameters, 3 for TECs (always!); 3, 5, or 6 for ATs
00430   unsigned int tecParams(3), atParams(0);
00431   if(nAtParameters_ == 3) atParams = 3;
00432   else if(nAtParameters_ == 5) atParams = 5;
00433   else atParams = 6;                            // <-- default value, recommended
00434   unsigned int nFitParams(0);
00435   if(!fitBeamSplitters_ || 
00436      (hitsAtTecPlus == 0 && beam.isAlignmentTube() ) ){
00437     tecParams = tecParams - 1;
00438     atParams = atParams - 1;
00439   }
00440   if(beam.isTecInternal()){
00441     nFitParams = tecParams;
00442   }
00443   else{
00444     nFitParams = atParams;
00445   }
00446   
00447   // fit parameter definitions
00448   double offset(0.), offsetError(0.), slope(0.), slopeError(0.),
00449     bsAngleParam(0.), phiAtMinusParam(0.), phiAtPlusParam(0.),
00450     atThetaSplitParam(0.);
00451   AlgebraicSymMatrix covMatrix;
00452   if(!fitBeamSplitters_ || (beam.isAlignmentTube() && hitsAtTecPlus == 0)){
00453     covMatrix = AlgebraicSymMatrix(nFitParams, 1);
00454   }
00455   else{
00456     covMatrix = AlgebraicSymMatrix(nFitParams - 1, 1);
00457   }
00458 
00459   this->fitter(beam, covMatrix, 
00460                hitsAtTecPlus, nFitParams, 
00461                hitPhi, hitPhiError, hitZprimeError, 
00462                zMin, zMax, bsAngleParam,
00463                offset, offsetError, slope, slopeError,
00464                phiAtMinusParam, phiAtPlusParam,
00465                atThetaSplitParam); 
00466   
00467   vector<GlobalPoint> globPtrack;
00468   GlobalPoint globPref;
00469   double chi2(0.);
00470 
00471   for(unsigned int hit = 0; hit < gHitZprime.size(); ++hit){
00472     
00473     // additional phi value (trackPhiRef) for trajectory calculation
00474     double trackPhi(0.), trackPhiRef(0.); 
00475     
00476     this->trackPhi(beam, hit, trackPhi, trackPhiRef,
00477                    offset, slope, bsAngleParam, 
00478                    phiAtMinusParam, phiAtPlusParam,
00479                    atThetaSplitParam, globHit);
00480 
00481     cout << "track phi = " << trackPhi 
00482          << ", hit phi = " << hitPhi[hit] 
00483          << ", zPrime = " << gHitZprime[hit] 
00484          << " r = " << globHit[hit].perp() << endl;
00485 
00486     this->globalTrackPoint(beam, hit, hitsAtTecPlus, 
00487                            trackPhi, trackPhiRef, 
00488                            globHit, globPtrack, globPref, 
00489                            hitPhiError);
00490 
00491     // calculate residuals = pred - hit (in global phi)
00492     const double phiResidual = globPtrack[hit].phi() - globHit[hit].phi();
00493     // pull calculation (FIX!!!)
00494     const double phiResidualPull = phiResidual / hitPhiError[hit];
00495     //       sqrt(hitPhiError[hit]*hitPhiError[hit] + 
00496     //     (offsetError*offsetError + globPtrack[hit].z()*globPtrack[hit].z() * slopeError*slopeError));
00497 
00498     // calculate chi2
00499     chi2 += phiResidual*phiResidual / (hitPhiError[hit]*hitPhiError[hit]);
00500     
00501     // fill histos
00502     h_res->Fill(phiResidual);
00503     // TECplus
00504     if(beam.isTecInternal(1)){
00505       h_pull->Fill(phiResidualPull);
00506       h_resTecPlus->Fill(phiResidual);
00507       h_resVsZTecPlus->Fill(globPtrack[hit].z(), phiResidual);
00508       // Ring 6
00509       if(beam.isRing6()){
00510         h_resVsHitTecPlus->Fill(hit+(beam.getBeamId()-1)/10*9+72, phiResidual);
00511       }
00512       // Ring 4
00513       else{
00514         h_resVsHitTecPlus->Fill(hit+beam.getBeamId()/10*9, phiResidual);
00515       }
00516     }
00517     // TECminus
00518     else if(beam.isTecInternal(-1)){
00519       h_pull->Fill(phiResidualPull);
00520       h_resTecMinus->Fill(phiResidual);
00521       h_resVsZTecMinus->Fill(globPtrack[hit].z(), phiResidual);
00522       // Ring 6
00523       if(beam.isRing6()){
00524         h_resVsHitTecMinus->Fill(hit+(beam.getBeamId()-101)/10*9+72, phiResidual);
00525       }
00526       // Ring 4
00527       else{
00528         h_resVsHitTecMinus->Fill(hit+(beam.getBeamId()-100)/10*9, phiResidual);
00529       }
00530     }
00531     // ATs
00532     else{
00533       h_pull->Fill(phiResidualPull);
00534       h_resAt->Fill(phiResidual);
00535       h_resVsZAt->Fill(globPtrack[hit].z(), phiResidual);
00536       h_resVsHitAt->Fill(hit+(beam.getBeamId()-200)/10*22, phiResidual);
00537     }
00538 
00539     this->buildTrajectory(beam, hit, gd, globPtrack, tsosLas, globPref);
00540   }
00541 
00542   cout << "chi^2 = " << chi2 << ", chi^2/ndof = " << chi2/(gHitZprime.size() - nFitParams) << endl;
00543   this->fitBeam(beam, covMatrix, hitsAtTecPlus, nFitParams,
00544                 offset, slope, globPtrack, bsAngleParam, chi2);
00545   
00546   cout << "bsAngleParam = " << bsAngleParam << endl;
00547 
00548   // fill histos
00549   // include slope, offset, covariance plots here
00550   h_chi2->Fill(chi2);
00551   h_chi2ndof->Fill(chi2/(gHitZprime.size() - nFitParams));
00552   if(bsAngleParam != 0.0){
00553     h_bsAngle->Fill(2.0*atan(0.5*bsAngleParam));
00554     h_bsAngleVsBeam->Fill(beam.getBeamId(), 2.0*atan(0.5*bsAngleParam));
00555   }
00556 }
00557 
00558 
00559 // --------- get hits, convert to global coordinates ---------------------------
00560 void TkLasBeamFitter::getLasHits(TkFittedLasBeam &beam, const SiStripLaserRecHit2D &hit, 
00561                                  vector<const GeomDetUnit*> &gd, vector<GlobalPoint> &globHit,
00562                                  unsigned int &hitsAtTecPlus)
00563 { 
00564   // get global position of LAS hits
00565   gd.push_back(geometry->idToDetUnit(hit.getDetId()));
00566   GlobalPoint globPtemp(gd.back()->toGlobal(hit.localPosition()));
00567 
00568   // testing: globPtemp should be right
00569   globHit.push_back(globPtemp);
00570 
00571   if(beam.isAlignmentTube()){
00572     if(abs(globPtemp.z()) > 112.3){
00573       if(globPtemp.z() < 112.3) gHitsAtTecMinus++ ;
00574       else hitsAtTecPlus++ ;
00575     }
00576   }
00577 }
00578 
00579 
00580 // ------------ parametrization functions for las beam fits ------------
00581 double TkLasBeamFitter::tecPlusFunction(double *x, double *par)
00582 {
00583   double z = x[0]; // 'primed'? -> yes!!!
00584 
00585   if(z < gBeamSplitterZprime){
00586     return par[0] + par[1] * z;
00587   } 
00588   else{
00589     if(gFitBeamSplitters){
00590       // par[2] = 2*tan(BeamSplitterAngle/2.0)
00591       return par[0] + par[1] * z - par[2] * (z - gBeamSplitterZprime)/gBeamR; 
00592     }
00593     else{
00594       return par[0] + par[1] * z - gBSparam * (z - gBeamSplitterZprime)/gBeamR; 
00595     }
00596   }
00597 }
00598 
00599 
00600 double TkLasBeamFitter::tecMinusFunction(double *x, double *par)
00601 {
00602   double z = x[0]; // 'primed'? -> yes!!!
00603 
00604   if(z > gBeamSplitterZprime){
00605     return par[0] + par[1] * z;
00606   } 
00607   else{
00608     if(gFitBeamSplitters){
00609       // par[2] = 2*tan(BeamSplitterAngle/2.0)
00610       return par[0] + par[1] * z + par[2] * (z - gBeamSplitterZprime)/gBeamR; 
00611     }
00612     else{
00613       return par[0] + par[1] * z + gBSparam * (z - gBeamSplitterZprime)/gBeamR; 
00614     }
00615   }
00616 }
00617  
00618 double TkLasBeamFitter::atFunction(double *x, double *par)
00619 {
00620   double z = x[0]; // 'primed'? -> yes!!!
00621   // TECminus
00622   if(z < -gBeamSplitterZprime - 2.0*gBeamZ0){
00623     return par[0] + par[1] * z;
00624   }
00625   // BarrelMinus
00626   else if(-gBeamSplitterZprime - 2.0*gBeamZ0 < z && z < -gBeamZ0){
00627     // z value includes module offset from main beam axis
00628     // TOB
00629     if(!gIsInnerBarrel){
00630       return par[0] + par[1] * z + gTOBparam * (par[2] + par[4]);
00631     }
00632     // TIB
00633     else{
00634       return par[0] + par[1] * z - gTIBparam * (par[2] - par[4]);
00635     }
00636   }
00637   // BarrelPlus
00638   else if(-gBeamZ0 < z && z < gBeamSplitterZprime){
00639     // z value includes module offset from main beam axis
00640     // TOB
00641     if(!gIsInnerBarrel){
00642       return par[0] + par[1] * z + gTOBparam * (par[3] - par[4]);
00643     }
00644     // TIB
00645     else{
00646       return par[0] + par[1] * z - gTIBparam * (par[3] + par[4]);
00647     }
00648   }
00649   // TECplus
00650   else{
00651     if(gFitBeamSplitters){
00652       // par[2] = 2*tan(BeamSplitterAngle/2.0)
00653       return par[0] + par[1] * z - par[5] * (z - gBeamSplitterZprime)/gBeamR; // BS par: 5, 4, or 2
00654     }
00655     else{
00656       return par[0] + par[1] * z - gBSparam * (z - gBeamSplitterZprime)/gBeamR;
00657     }
00658   }
00659 }
00660 
00661 
00662 // ------------ perform fit of beams ------------------------------------
00663 void TkLasBeamFitter::fitter(TkFittedLasBeam &beam, AlgebraicSymMatrix &covMatrix, 
00664                              unsigned int &hitsAtTecPlus, unsigned int &nFitParams,
00665                              vector<double> &hitPhi, vector<double> &hitPhiError, vector<double> &hitZprimeError,
00666                              double &zMin, double &zMax, double &bsAngleParam, 
00667                              double &offset, double &offsetError, double &slope, double &slopeError,
00668                              double &phiAtMinusParam, double &phiAtPlusParam, double &atThetaSplitParam)
00669 {
00670   TGraphErrors *lasData = new TGraphErrors(gHitZprime.size(), 
00671                                            &(gHitZprime[0]), &(hitPhi[0]), 
00672                                            &(hitZprimeError[0]), &(hitPhiError[0]));
00673   
00674   // do fit (R = entire range)
00675   if(beam.isTecInternal(1)){
00676     TF1 tecPlus("tecPlus", tecPlusFunction, zMin, zMax, nFitParams );
00677     tecPlus.SetParameter( 1, 0 ); // slope
00678     tecPlus.SetParameter( nFitParams - 1, 0 ); // BS 
00679     lasData->Fit("tecPlus", "R"); // "R", "RV" or "RQ"
00680   }
00681   else if(beam.isTecInternal(-1)){
00682     TF1 tecMinus("tecMinus", tecMinusFunction, zMin, zMax, nFitParams );
00683     tecMinus.SetParameter( 1, 0 ); // slope
00684     tecMinus.SetParameter( nFitParams - 1, 0 ); // BS 
00685     lasData->Fit("tecMinus", "R");
00686   }
00687   else{
00688     TF1 at("at", atFunction, zMin, zMax, nFitParams );
00689     at.SetParameter( 1, 0 ); // slope
00690     at.SetParameter( nFitParams - 1, 0 ); // BS 
00691     lasData->Fit("at","R");
00692   }
00693   
00694   // get values and errors for offset and slope
00695   gMinuit->GetParameter(0, offset, offsetError);
00696   gMinuit->GetParameter(1, slope, slopeError);
00697 
00698   // additional AT parameters
00699   // define param errors that are not used later
00700   double bsAngleParamError(0.), phiAtMinusParamError(0.),
00701     phiAtPlusParamError(0.), atThetaSplitParamError(0.);
00702 
00703   if(beam.isAlignmentTube()){
00704     gMinuit->GetParameter(2, phiAtMinusParam, phiAtMinusParamError);
00705     gMinuit->GetParameter(3, phiAtPlusParam, phiAtPlusParamError);
00706     gMinuit->GetParameter(4, atThetaSplitParam, atThetaSplitParamError);
00707   }
00708   // get Beam Splitter parameters
00709   if(fitBeamSplitters_){
00710     if(beam.isAlignmentTube() && hitsAtTecPlus == 0){
00711       bsAngleParam = gBSparam;
00712     }
00713     else{
00714       gMinuit->GetParameter( nFitParams - 1 , bsAngleParam, bsAngleParamError);
00715     }
00716   }
00717   else{
00718     bsAngleParam = gBSparam;
00719   }
00720 
00721   // fill covariance matrix
00722   vector<double> vec( covMatrix.num_col() * covMatrix.num_col() );
00723   gMinuit->mnemat( &vec[0], covMatrix.num_col() );
00724   for(int col = 0; col < covMatrix.num_col(); col++){
00725     for(int row = 0; row < covMatrix.num_col(); row++){
00726       covMatrix[col][row] = vec[row + covMatrix.num_col()*col];
00727     }
00728   }
00729   // compute correlation between parameters
00730 //   double corr01 = covMatrix[1][0]/(offsetError*slopeError);
00731 
00732   delete lasData;
00733 }
00734 
00735 
00736 // -------------- calculate track phi value ----------------------------------
00737 void TkLasBeamFitter::trackPhi(TkFittedLasBeam &beam, unsigned int &hit, 
00738                                double &trackPhi, double &trackPhiRef,
00739                                double &offset, double &slope, double &bsAngleParam,
00740                                double &phiAtMinusParam, double &phiAtPlusParam,
00741                                double &atThetaSplitParam, vector<GlobalPoint> &globHit)
00742 {
00743   // TECplus
00744   if(beam.isTecInternal(1)){
00745     if(gHitZprime[hit] < gBeamSplitterZprime){
00746       trackPhi = offset + slope * gHitZprime[hit];
00747       trackPhiRef = offset + slope * (gHitZprime[hit] + 1.0);
00748     }
00749     else{
00750       trackPhi = offset + slope * gHitZprime[hit] 
00751         - bsAngleParam * (gHitZprime[hit] - gBeamSplitterZprime)/gBeamR;
00752       trackPhiRef = offset + slope * (gHitZprime[hit] + 1.0)
00753         - bsAngleParam * ((gHitZprime[hit] + 1.0) - gBeamSplitterZprime)/gBeamR;
00754     }
00755   }
00756   // TECminus
00757   else if(beam.isTecInternal(-1)){
00758     if(gHitZprime[hit] > gBeamSplitterZprime){
00759       trackPhi = offset + slope * gHitZprime[hit];
00760       trackPhiRef = offset + slope * (gHitZprime[hit] + 1.0);
00761     }
00762     else{
00763       trackPhi = offset + slope * gHitZprime[hit] 
00764         + bsAngleParam * (gHitZprime[hit] - gBeamSplitterZprime)/gBeamR;
00765       trackPhiRef = offset + slope * (gHitZprime[hit] + 1.0)
00766         + bsAngleParam * ((gHitZprime[hit] + 1.0) - gBeamSplitterZprime)/gBeamR;
00767     }
00768   }
00769   // ATs
00770   else{
00771     // TECminus
00772     if(gHitZprime[hit] < -gBeamSplitterZprime - 2.0*gBeamZ0){
00773       trackPhi = offset + slope * gHitZprime[hit];
00774       trackPhiRef = offset + slope * (gHitZprime[hit] + 1.0);
00775     }
00776     // BarrelMinus
00777     else if(-gBeamSplitterZprime - 2.0*gBeamZ0 < gHitZprime[hit] && gHitZprime[hit] < -gBeamZ0){
00778       if(!gIsInnerBarrel){
00779         trackPhi = offset + slope * gHitZprime[hit] + gTOBparam * (phiAtMinusParam + atThetaSplitParam); 
00780       }
00781       else{
00782         trackPhi = offset + slope * gHitZprime[hit] - gTIBparam * (phiAtMinusParam - atThetaSplitParam);
00783       }
00784       trackPhiRef = offset + slope * (gHitZprime[hit] + abs(gBarrelModuleOffset[hit-gHitsAtTecMinus]));
00785     }
00786     // BarrelPlus
00787     else if(-gBeamZ0 < gHitZprime[hit] && gHitZprime[hit] < gBeamSplitterZprime){
00788       if(!gIsInnerBarrel){
00789         trackPhi = offset + slope * gHitZprime[hit] + gTOBparam * (phiAtPlusParam - atThetaSplitParam);
00790       }
00791       else{
00792         trackPhi = offset + slope * gHitZprime[hit] - gTIBparam * (phiAtPlusParam + atThetaSplitParam);
00793       }
00794       trackPhiRef = offset + slope * (gHitZprime[hit] + abs(gBarrelModuleOffset[hit-gHitsAtTecMinus]));
00795     }
00796     // TECplus
00797     else{
00798       trackPhi = offset + slope * gHitZprime[hit] 
00799         - bsAngleParam * (gHitZprime[hit] - gBeamSplitterZprime)/gBeamR;
00800       trackPhiRef = offset + slope * (gHitZprime[hit] + 1.0)
00801         - bsAngleParam * ((gHitZprime[hit] + 1.0) - gBeamSplitterZprime)/gBeamR;
00802     }
00803   }
00804 }
00805 
00806 
00807 // -------------- calculate global track points, hit residuals, chi2 ----------------------------------
00808 void TkLasBeamFitter::globalTrackPoint(TkFittedLasBeam &beam, 
00809                                        unsigned int &hit, unsigned int &hitsAtTecPlus,
00810                                        double &trackPhi, double &trackPhiRef, 
00811                                        vector<GlobalPoint> &globHit, vector<GlobalPoint> &globPtrack,
00812                                        GlobalPoint &globPref, vector<double> &hitPhiError)
00813 {
00814   // TECs
00815   if(beam.isTecInternal(0)){
00816     globPtrack.push_back(GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhi, globHit[hit].z())));
00817     globPref = GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhiRef, globHit[hit].z() + 1.0));
00818   }
00819   // ATs
00820   else{
00821     // TECminus
00822     if(hit < gHitsAtTecMinus){ // gHitZprime[hit] < -gBeamSplitterZprime - 2.0*gBeamZ0
00823       globPtrack.push_back(GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhi, globHit[hit].z())));
00824       globPref = GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhiRef, globHit[hit].z() + 1.0));
00825     }
00826     // TECplus
00827     else if(hit > gHitZprime.size() - hitsAtTecPlus - 1){ // gHitZprime[hit] > gBeamSplitterZprime
00828       globPtrack.push_back(GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhi, globHit[hit].z())));
00829       globPref = GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhiRef, globHit[hit].z() + 1.0));
00830     }
00831     // Barrel
00832     else{
00833       globPtrack.push_back(GlobalPoint(GlobalPoint::Cylindrical(globHit[hit].perp(), trackPhi, globHit[hit].z())));
00834       globPref = GlobalPoint(GlobalPoint::Cylindrical(gBeamR, trackPhiRef, globHit[hit].z()));
00835     }
00836   }
00837 }
00838 
00839 
00840 // ----------- create TrajectoryStateOnSurface for each track hit ----------------------------------------------
00841 void TkLasBeamFitter::buildTrajectory(TkFittedLasBeam &beam, unsigned int &hit, 
00842                                       vector<const GeomDetUnit*> &gd, vector<GlobalPoint> &globPtrack,
00843                                       vector<TrajectoryStateOnSurface> &tsosLas, GlobalPoint &globPref)
00844 {
00845   const MagneticField* magneticField = fieldHandle.product();
00846   GlobalVector trajectoryState;
00847   
00848   // TECplus
00849   if(beam.isTecInternal(1)){
00850     trajectoryState = GlobalVector(globPref-globPtrack[hit]);
00851   }
00852   // TECminus
00853   else if(beam.isTecInternal(-1)){
00854     trajectoryState = GlobalVector(globPtrack[hit]-globPref);
00855   }
00856   // ATs
00857   else{
00858     // TECminus
00859     if(gHitZprime[hit] < -gBeamSplitterZprime - 2.0*gBeamZ0){
00860       trajectoryState = GlobalVector(globPtrack[hit]-globPref);
00861     }
00862     // TECplus
00863     else if(gHitZprime[hit] > gBeamSplitterZprime){
00864       trajectoryState = GlobalVector(globPref-globPtrack[hit]);
00865     }
00866     // Barrel
00867     else{
00868       trajectoryState = GlobalVector(globPtrack[hit]-globPref);
00869     }
00870   }     
00871 //   cout << "trajectory: " << trajectoryState << endl;                 
00872   const FreeTrajectoryState ftsLas = FreeTrajectoryState(globPtrack[hit],trajectoryState,0,magneticField);
00873   tsosLas.push_back(TrajectoryStateOnSurface(ftsLas,gd[hit]->surface(),
00874                                              SurfaceSideDefinition::beforeSurface));
00875 }
00876 
00877 
00878 //---------------------- set beam parameters for fittedBeams ---------------------------------
00879 bool TkLasBeamFitter::fitBeam(TkFittedLasBeam &beam, AlgebraicSymMatrix &covMatrix, 
00880                               unsigned int &hitsAtTecPlus, unsigned int &nFitParams,
00881                               double &offset, double &slope, vector<GlobalPoint> &globPtrack,
00882                               double &bsAngleParam, double &chi2)
00883 {
00884   // set beam parameters for beam output
00885   unsigned int paramType(0);
00886   if(!fitBeamSplitters_) paramType = 1;
00887   if(beam.isAlignmentTube() && hitsAtTecPlus == 0) paramType = 0;
00888 //   const unsigned int nPedeParams = nFitParams + paramType;
00889 
00890   // test without BS params
00891   const unsigned int nPedeParams(nFitParams);
00892 //   cout << "number of Pede parameters: " << nPedeParams << endl;
00893 
00894   std::vector<TkFittedLasBeam::Scalar> params(nPedeParams);
00895   params[0] = offset;
00896   params[1] = slope;
00897   // no BS parameter for AT beams without TECplus hits
00898 //   if(beam.isTecInternal() || hitsAtTecPlus > 0) params[2] = bsAngleParam;
00899 
00900   AlgebraicMatrix derivatives(gHitZprime.size(), nPedeParams);
00901   // fill derivatives matrix with local track derivatives
00902   for(unsigned int hit = 0; hit < gHitZprime.size(); ++hit){
00903     
00904     // d(delta phi)/d(offset) is identical for every hit
00905     derivatives[hit][0] = 1.0;
00906 
00907     // d(delta phi)/d(slope) and d(delta phi)/d(bsAngleParam) depend on parametrizations
00908     // TECplus
00909     if(beam.isTecInternal(1)){
00910       derivatives[hit][1] = globPtrack[hit].z();
00911 //       if(gHitZprime[hit] < gBeamSplitterZprime){
00912 //      derivatives[hit][2] = 0.0;
00913 //       }
00914 //       else{
00915 //      derivatives[hit][2] = - (globPtrack[hit].z() - gBeamSplitterZprime) / gBeamR;
00916 //       }
00917     }
00918     // TECminus
00919     else if(beam.isTecInternal(-1)){
00920       derivatives[hit][1] = globPtrack[hit].z();
00921 //       if(gHitZprime[hit] > gBeamSplitterZprime){
00922 //      derivatives[hit][2] = 0.0;
00923 //       }
00924 //       else{
00925 //      derivatives[hit][2] = (globPtrack[hit].z() - gBeamSplitterZprime) / gBeamR;
00926 //       }
00927     }
00928     // ATs
00929     else{
00930       // TECminus
00931       if(gHitZprime[hit] < -gBeamSplitterZprime - 2.0*gBeamZ0){
00932         derivatives[hit][1] = globPtrack[hit].z();
00933 //      if(hitsAtTecPlus > 0){
00934 //        derivatives[hit][2] = 0.0;
00935 //      }
00936       }
00937       // TECplus
00938       else if(gHitZprime[hit] > gBeamSplitterZprime){
00939         derivatives[hit][1] = globPtrack[hit].z();
00940 //      if(hitsAtTecPlus > 0){
00941 //        derivatives[hit][2] = - (globPtrack[hit].z() - gBeamSplitterZprime) / gBeamR;
00942 //      }
00943       }
00944       // Barrel
00945       else{
00946         derivatives[hit][1] = globPtrack[hit].z() - gBarrelModuleOffset[hit-gHitsAtTecMinus];
00947 //      if(hitsAtTecPlus > 0){
00948 //        derivatives[hit][2] = 0.0;
00949 //      }
00950       }
00951     }
00952   }
00953 
00954   unsigned int firstFixedParam(covMatrix.num_col()); // FIXME! --> no, is fine!!!
00955 //   unsigned int firstFixedParam = nPedeParams - 1;
00956 //   if(beam.isAlignmentTube() && hitsAtTecPlus == 0) firstFixedParam = nPedeParams;
00957 //   cout << "first fixed parameter: " << firstFixedParam << endl;
00958   // set fit results
00959   beam.setParameters(paramType, params, covMatrix, derivatives, firstFixedParam, chi2);
00960 
00961   return true; // return false in case of problems
00962 }
00963 
00964 
00965 //---------------------------------------------------------------------------------------
00966 //define this as a plug-in
00967 DEFINE_FWK_MODULE(TkLasBeamFitter);