CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_1/src/RecoTracker/CkfPattern/src/GroupedCkfTrajectoryBuilder.cc

Go to the documentation of this file.
00001 
00002 #include "RecoTracker/CkfPattern/interface/GroupedCkfTrajectoryBuilder.h"
00003 #include "TrajectorySegmentBuilder.h"
00004 
00005 
00006 #include "TrackingTools/DetLayers/interface/DetLayer.h"
00007 #include "TrackingTools/PatternTools/interface/TrajMeasLessEstim.h"
00008 
00009 #include "TrackingTools/KalmanUpdators/interface/KFUpdator.h"
00010 #include "TrackingTools/KalmanUpdators/interface/Chi2MeasurementEstimator.h"
00011 #include "TrackingTools/TrackFitters/interface/KFTrajectoryFitter.h"
00012 #include "RecoTracker/CkfPattern/interface/GroupedTrajCandLess.h"
00013 #include "TrackingTools/TrajectoryFiltering/interface/RegionalTrajectoryFilter.h"
00014 #include "TrackingTools/PatternTools/interface/TempTrajectory.h"
00015 #include "RecoTracker/MeasurementDet/interface/MeasurementTracker.h"
00016 #include "TrackingTools/MeasurementDet/interface/LayerMeasurements.h"
00017 #include "TrackingTools/Records/interface/TrackingComponentsRecord.h"
00018 #include "TrackingTools/DetLayers/interface/DetGroup.h"
00019 #include "RecoTracker/TkDetLayers/interface/GeometricSearchTracker.h"
00020 #include "TrackingTools/Records/interface/TransientRecHitRecord.h"
00021 #include "TrackingTools/TransientTrackingRecHit/interface/TransientTrackingRecHitBuilder.h"
00022 #include "TrackingTools/PatternTools/interface/TrajectoryMeasurement.h"
00023 
00024 #include "TrackingTools/PatternTools/interface/TrajectoryStateUpdator.h"
00025 #include "TrackingTools/KalmanUpdators/interface/KFUpdator.h"
00026 #include "TrackingTools/PatternTools/interface/Trajectory.h"
00027 #include "TrackingTools/PatternTools/interface/TrajMeasLessEstim.h"
00028 #include "TrackingTools/TrajectoryState/interface/BasicSingleTrajectoryState.h"
00029 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00030 #include "TrackingTools/PatternTools/interface/TransverseImpactPointExtrapolator.h"
00031 
00032 // only included for RecHit comparison operator:
00033 #include "TrackingTools/TrajectoryCleaning/interface/TrajectoryCleanerBySharedHits.h"
00034 
00035 // for looper reconstruction
00036 #include "TrackingTools/GeomPropagators/interface/HelixBarrelCylinderCrossing.h"
00037 #include "TrackingTools/GeomPropagators/interface/HelixBarrelPlaneCrossingByCircle.h"
00038 #include "TrackingTools/GeomPropagators/interface/HelixArbitraryPlaneCrossing.h"
00039 
00040 
00041 #include <algorithm> 
00042 
00043 using namespace std;
00044 
00045 //#define DBG2_GCTB
00046 
00047 //#define STANDARD_INTERMEDIARYCLEAN
00048 
00049 #ifdef STANDARD_INTERMEDIARYCLEAN
00050 #include "RecoTracker/CkfPattern/interface/IntermediateTrajectoryCleaner.h"
00051 #endif
00052 
00053 /* ====== B.M. to be ported layer ===========
00054 #ifdef DBG_GCTB
00055 #include "RecoTracker/CkfPattern/src/ShowCand.h"
00056 #endif
00057 // #define DBG2_GCTB
00058 #ifdef DBG2_GCTB
00059 #include "RecoTracker/CkfPattern/src/SimIdPrinter.h"
00060 #include "Tracker/TkDebugTools/interface/LayerFinderByDet.h"
00061 #include "Tracker/TkLayout/interface/TkLayerName.h"
00062 #endif
00063 =================================== */
00064 
00065 
00066 GroupedCkfTrajectoryBuilder::
00067 GroupedCkfTrajectoryBuilder(const edm::ParameterSet&              conf,
00068                             const TrajectoryStateUpdator*         updator,
00069                             const Propagator*                     propagatorAlong,
00070                             const Propagator*                     propagatorOpposite,
00071                             const Chi2MeasurementEstimatorBase*   estimator,
00072                             const TransientTrackingRecHitBuilder* recHitBuilder,
00073                             const MeasurementTracker*             measurementTracker,
00074                             const TrajectoryFilter*               filter,
00075                             const TrajectoryFilter*               inOutFilter):
00076 
00077 
00078   BaseCkfTrajectoryBuilder(conf,
00079                            updator, propagatorAlong,propagatorOpposite,
00080                            estimator, recHitBuilder, measurementTracker, filter, inOutFilter)
00081 {
00082   // fill data members from parameters (eventually data members could be dropped)
00083   //
00084   theMaxCand                  = conf.getParameter<int>("maxCand");
00085 
00086   theLostHitPenalty           = conf.getParameter<double>("lostHitPenalty");
00087   theFoundHitBonus            = conf.getParameter<double>("foundHitBonus");
00088   theIntermediateCleaning     = conf.getParameter<bool>("intermediateCleaning");
00089   theAlwaysUseInvalid         = conf.getParameter<bool>("alwaysUseInvalidHits");
00090   theLockHits                 = conf.getParameter<bool>("lockHits");
00091   theBestHitOnly              = conf.getParameter<bool>("bestHitOnly");
00092   theMinNrOf2dHitsForRebuild  = 2;
00093   theRequireSeedHitsInRebuild = conf.getParameter<bool>("requireSeedHitsInRebuild");
00094   theMinNrOfHitsForRebuild    = max(0,conf.getParameter<int>("minNrOfHitsForRebuild"));
00095   maxPtForLooperReconstruction     = conf.existsAs<double>("maxPtForLooperReconstruction") ? 
00096     conf.getParameter<double>("maxPtForLooperReconstruction") : 0;
00097   maxDPhiForLooperReconstruction     = conf.existsAs<double>("maxDPhiForLooperReconstruction") ? 
00098     conf.getParameter<double>("maxDPhiForLooperReconstruction") : 2.0;
00099 
00100 
00101   /* ======= B.M. to be ported layer ===========
00102   bool setOK = thePropagator->setMaxDirectionChange(1.6);
00103   if (!setOK) 
00104     cout  << "GroupedCkfTrajectoryBuilder WARNING: "
00105           << "propagator does not support setMaxDirectionChange" 
00106           << endl;
00107   //   addStopCondition(theMinPtStopCondition);
00108 
00109   theConfigurableCondition = createAlgo<TrajectoryFilter>(componentConfig("StopCondition"));
00110   ===================================== */
00111 
00112 }
00113 
00114 /*
00115   void GroupedCkfTrajectoryBuilder::setEvent(const edm::Event& event) const
00116   {
00117   theMeasurementTracker->update(event);
00118 }
00119 */
00120 
00121 GroupedCkfTrajectoryBuilder::TrajectoryContainer 
00122 GroupedCkfTrajectoryBuilder::trajectories (const TrajectorySeed& seed) const 
00123 {
00124   TrajectoryContainer ret; 
00125   ret.reserve(10);
00126   buildTrajectories(seed, ret, 0);
00127   return ret; 
00128 }
00129 
00130 GroupedCkfTrajectoryBuilder::TrajectoryContainer 
00131 GroupedCkfTrajectoryBuilder::trajectories (const TrajectorySeed& seed, 
00132                                            const TrackingRegion& region) const
00133 {
00134   TrajectoryContainer ret; 
00135   ret.reserve(10);
00136   RegionalTrajectoryFilter regionalCondition(region);
00137   buildTrajectories(seed, ret, &regionalCondition);
00138   return ret; 
00139 }
00140 
00141 void 
00142 GroupedCkfTrajectoryBuilder::trajectories (const TrajectorySeed& seed, GroupedCkfTrajectoryBuilder::TrajectoryContainer &ret) const 
00143 {
00144   buildTrajectories(seed,ret,0);
00145 }
00146 
00147 void
00148 GroupedCkfTrajectoryBuilder::trajectories (const TrajectorySeed& seed, 
00149                                             GroupedCkfTrajectoryBuilder::TrajectoryContainer &ret,
00150                                             const TrackingRegion& region) const
00151 {
00152   RegionalTrajectoryFilter regionalCondition(region);
00153   buildTrajectories(seed,ret,&regionalCondition);
00154 }
00155 
00156 void  
00157 GroupedCkfTrajectoryBuilder::rebuildSeedingRegion(const TrajectorySeed& seed,
00158                                                   TrajectoryContainer& result) const {    
00159   TempTrajectory startingTraj = createStartingTrajectory( seed);
00160   TempTrajectoryContainer work;
00161 
00162   TrajectoryContainer final;
00163 
00164   work.reserve(result.size());
00165   for (TrajectoryContainer::iterator traj=result.begin();
00166        traj!=result.end(); ++traj) {
00167     if(traj->isValid()) work.push_back(TempTrajectory(*traj));
00168   }
00169 
00170   rebuildSeedingRegion(startingTraj,work);
00171   final.reserve(work.size());
00172 
00173   for (TempTrajectoryContainer::iterator traj=work.begin();
00174        traj!=work.end(); ++traj) {
00175     final.push_back(traj->toTrajectory());
00176   }
00177   
00178   result.swap(final);
00179   
00180 }
00181 
00182 void
00183 GroupedCkfTrajectoryBuilder::buildTrajectories (const TrajectorySeed& seed,
00184                                                 GroupedCkfTrajectoryBuilder::TrajectoryContainer &result,
00185                                                 const TrajectoryFilter* regionalCondition) const
00186 {
00187   //
00188   // Build trajectory outwards from seed
00189   //
00190 
00191   analyseSeed( seed);
00192 
00193   TempTrajectory startingTraj = createStartingTrajectory( seed);
00194 
00195   work_.clear();
00196   const bool inOut = true;
00197   groupedLimitedCandidates( startingTraj, regionalCondition, theForwardPropagator, inOut, work_);
00198   if ( work_.empty() )  return ;
00199 
00200 
00201 
00202   /*  rebuilding is de-coupled from standard building
00203   //
00204   // try to additional hits in the seeding region
00205   //
00206   if ( theMinNrOfHitsForRebuild>0 ) {
00207     // reverse direction
00208     //thePropagator->setPropagationDirection(oppositeDirection(seed.direction()));
00209     // rebuild part of the trajectory
00210     rebuildSeedingRegion(startingTraj,work);
00211   }
00212 
00213   */
00214 
00215   result.reserve(work_.size());
00216   for (TempTrajectoryContainer::const_iterator it = work_.begin(), ed = work_.end(); it != ed; ++it) {
00217       result.push_back( it->toTrajectory() );
00218   }
00219 
00220   work_.clear(); 
00221   if (work_.capacity() > work_MaxSize_) {  TempTrajectoryContainer().swap(work_); work_.reserve(work_MaxSize_/2); }
00222 
00223   analyseResult(result);
00224 
00225   LogDebug("CkfPattern")<< "GroupedCkfTrajectoryBuilder: returning result of size " << result.size();
00226 
00227 }
00228 
00229 
00230 void 
00231 GroupedCkfTrajectoryBuilder::groupedLimitedCandidates (TempTrajectory& startingTraj, 
00232                                                        const TrajectoryFilter* regionalCondition,
00233                                                        const Propagator* propagator, 
00234                                                        bool inOut,
00235                                                        TempTrajectoryContainer& result) const
00236 {
00237   unsigned int nIter=1;
00238   TempTrajectoryContainer candidates;
00239   TempTrajectoryContainer newCand;
00240   candidates.push_back( startingTraj);
00241 
00242   while ( !candidates.empty()) {
00243 
00244     newCand.clear();
00245     for (TempTrajectoryContainer::iterator traj=candidates.begin();
00246          traj!=candidates.end(); traj++) {
00247       if ( !advanceOneLayer(*traj, regionalCondition, propagator, inOut, newCand, result) ) {
00248         LogDebug("CkfPattern")<< "GCTB: terminating after advanceOneLayer==false";
00249         continue;
00250       }
00251 
00252       LogDebug("CkfPattern")<<"newCand(1): after advanced one layer:\n"<<PrintoutHelper::dumpCandidates(newCand);
00253 
00254       if ((int)newCand.size() > theMaxCand) {
00255         //ShowCand()(newCand);
00256 
00257         sort( newCand.begin(), newCand.end(), GroupedTrajCandLess(theLostHitPenalty,theFoundHitBonus));
00258         newCand.erase( newCand.begin()+theMaxCand, newCand.end());
00259       }
00260       LogDebug("CkfPattern")<<"newCand(2): after removing extra candidates.\n"<<PrintoutHelper::dumpCandidates(newCand);
00261     }
00262 
00263     LogDebug("CkfPattern") << "newCand.size() at end = " << newCand.size();
00264 /*
00265     if (theIntermediateCleaning) {
00266       candidates.clear();
00267       candidates = groupedIntermediaryClean(newCand);
00268     } else {
00269       candidates.swap(newCand);
00270     }
00271 */
00272     if (theIntermediateCleaning) {
00273 #ifdef STANDARD_INTERMEDIARYCLEAN
00274         IntermediateTrajectoryCleaner::clean(newCand);  
00275 #else 
00276         groupedIntermediaryClean(newCand);
00277 #endif  
00278 
00279     }   
00280     candidates.swap(newCand);
00281 
00282     LogDebug("CkfPattern") <<"candidates(3): "<<result.size()<<" candidates after "<<nIter++<<" groupedCKF iteration: \n"
00283                            <<PrintoutHelper::dumpCandidates(result)
00284                            <<"\n "<<candidates.size()<<" running candidates are: \n"
00285                            <<PrintoutHelper::dumpCandidates(candidates);
00286   }
00287 }
00288 
00289 std::string whatIsTheNextStep(TempTrajectory& traj , std::pair<TrajectoryStateOnSurface,std::vector<const DetLayer*> >& stateAndLayers){
00290   std::stringstream buffer;
00291   vector<const DetLayer*> & nl = stateAndLayers.second;
00292 #include "TrackingTools/DetLayers/interface/BarrelDetLayer.h"
00293 #include "TrackingTools/DetLayers/interface/ForwardDetLayer.h"
00294   //B.M. TkLayerName layerName;
00295   //B.M. buffer << "Started from " << layerName(traj.lastLayer()) 
00296   const BarrelDetLayer* sbdl = dynamic_cast<const BarrelDetLayer*>(traj.lastLayer());
00297   const ForwardDetLayer* sfdl = dynamic_cast<const ForwardDetLayer*>(traj.lastLayer());
00298   if (sbdl) {
00299     buffer << "Started from " << traj.lastLayer() << " r=" << sbdl->specificSurface().radius() 
00300            << " phi=" << sbdl->specificSurface().phi() << endl;
00301   } else if (sfdl) {
00302     buffer << "Started from " << traj.lastLayer() << " z " << sfdl->specificSurface().position().z()
00303            << " phi " << sfdl->specificSurface().phi() << endl;
00304   }
00305   buffer << "Trying to go to";
00306   for ( vector<const DetLayer*>::iterator il=nl.begin();
00307         il!=nl.end(); il++){ 
00308     //B.M. buffer << " " << layerName(*il)  << " " << *il << endl;
00309     const BarrelDetLayer* bdl = dynamic_cast<const BarrelDetLayer*>(*il);
00310     const ForwardDetLayer* fdl = dynamic_cast<const ForwardDetLayer*>(*il);
00311     
00312     if (bdl) buffer << " r " << bdl->specificSurface().radius() << endl;
00313     if (fdl) buffer << " z " << fdl->specificSurface().position().z() << endl;
00314     //buffer << " " << *il << endl;   
00315   }
00316   return buffer.str();
00317 }
00318 
00319 std::string whatIsTheStateToUse(TrajectoryStateOnSurface &initial, TrajectoryStateOnSurface & stateToUse, const DetLayer * l){
00320   std::stringstream buffer;
00321   buffer << "GCTB: starting from " 
00322          << " r / phi / z = " << stateToUse.globalPosition().perp()
00323          << " / " << stateToUse.globalPosition().phi()
00324          << " / " << stateToUse.globalPosition().z() 
00325          << " , pt / phi / pz /charge = " 
00326          << stateToUse.globalMomentum().perp() << " / "  
00327          << stateToUse.globalMomentum().phi() << " / " 
00328          << stateToUse.globalMomentum().z() << " / " 
00329          << stateToUse.charge()
00330          << " for layer at "<< l << endl;
00331   buffer << "     errors:";
00332   for ( int i=0; i<5; i++ )  buffer << " " << sqrt(stateToUse.curvilinearError().matrix()(i,i));
00333   buffer << endl;
00334   
00335   //buffer << "GCTB: starting from r / phi / z = " << initial.globalPosition().perp()
00336   //<< " / " << initial.globalPosition().phi()
00337   //<< " / " << initial.globalPosition().z() << " , pt / pz = " 
00338   //<< initial.globalMomentum().perp() << " / " 
00339   //<< initial.globalMomentum().z() << " for layer at "
00340   //<< l << endl;
00341   //buffer << "     errors:";
00342   //for ( int i=0; i<5; i++ )  buffer << " " << sqrt(initial.curvilinearError().matrix()(i,i));
00343   //buffer << endl;
00344   return buffer.str();
00345 }
00346 
00347 
00348 bool 
00349 GroupedCkfTrajectoryBuilder::advanceOneLayer (TempTrajectory& traj, 
00350                                               const TrajectoryFilter* regionalCondition, 
00351                                               const Propagator* propagator,
00352                                               bool inOut,
00353                                               TempTrajectoryContainer& newCand, 
00354                                               TempTrajectoryContainer& result) const
00355 {
00356   std::pair<TSOS,std::vector<const DetLayer*> > stateAndLayers = findStateAndLayers(traj);
00357   if(maxPtForLooperReconstruction>0){
00358     if(
00359        //stateAndLayers.second.size()==0 &&
00360        traj.lastLayer()->location()==0 && 
00361        stateAndLayers.first.globalMomentum().perp()<maxPtForLooperReconstruction &&
00362        stateAndLayers.first.globalMomentum().perp()>0.3)
00363       stateAndLayers.second.push_back(traj.lastLayer());
00364   }
00365 
00366   vector<const DetLayer*>::iterator layerBegin = stateAndLayers.second.begin();
00367   vector<const DetLayer*>::iterator layerEnd   = stateAndLayers.second.end();
00368 
00369   //   if (nl.empty()) {
00370   //     addToResult(traj,result,inOut);
00371   //     return false;
00372   //   }
00373   
00374   LogDebug("CkfPattern")<<whatIsTheNextStep(traj, stateAndLayers);
00375   
00376   bool foundSegments(false);
00377   bool foundNewCandidates(false);
00378   for ( vector<const DetLayer*>::iterator il=layerBegin; 
00379         il!=layerEnd; il++) {
00380 
00381     TSOS stateToUse = stateAndLayers.first;
00382 
00383     double dPhiCacheForLoopersReconstruction(0);
00384     if ((*il)==traj.lastLayer()){
00385       if(maxPtForLooperReconstruction>0){
00386         // ------ For loopers reconstruction
00387         //cout<<" self propagating in advanceOneLayer (for loopers) \n";
00388         const BarrelDetLayer* sbdl = dynamic_cast<const BarrelDetLayer*>(traj.lastLayer());
00389         if(sbdl){
00390           HelixBarrelCylinderCrossing cylinderCrossing(stateToUse.globalPosition(),
00391                                                        stateToUse.globalMomentum(),
00392                                                        stateToUse.transverseCurvature(),
00393                                                        propagator->propagationDirection(),
00394                                                        sbdl->specificSurface());
00395           if(!cylinderCrossing.hasSolution()) continue;
00396           GlobalPoint starting = stateToUse.globalPosition();
00397           GlobalPoint target1 = cylinderCrossing.position1();
00398           GlobalPoint target2 = cylinderCrossing.position2();
00399           
00400           GlobalPoint farther = fabs(starting.phi()-target1.phi()) > fabs(starting.phi()-target2.phi()) ?
00401             target1 : target2;
00402         
00403           const Bounds& bounds( sbdl->specificSurface().bounds());
00404           float length = bounds.length() / 2.f;
00405         
00406           /*
00407             cout << "starting: " << starting << endl;
00408             cout << "target1: " << target1 << endl;
00409             cout << "target2: " << target2 << endl;
00410             cout << "dphi: " << (target1.phi()-target2.phi()) << endl;
00411             cout << "length: " << length << endl;
00412           */
00413         
00414           /*
00415           float deltaZ = bounds.thickness()/2.f/fabs(tan(stateToUse.globalDirection().theta()) ) ;
00416           if(stateToUse.hasError())
00417             deltaZ += 3*sqrt(stateToUse.cartesianError().position().czz());
00418           if( fabs(farther.z()) > length + deltaZ ) continue;
00419           */
00420           if(fabs(farther.z())*0.95>length) continue;
00421 
00422           Geom::Phi<double> tmpDphi = target1.phi()-target2.phi();
00423           if(fabs(tmpDphi)>maxDPhiForLooperReconstruction) continue;
00424           GlobalPoint target((target1.x()+target2.x())/2,
00425                              (target1.y()+target2.y())/2,
00426                              (target1.z()+target2.z())/2);
00427           
00428           //cout << "target: " << target << endl;
00429           
00430 
00431           
00432           TransverseImpactPointExtrapolator extrapolator;
00433           stateToUse = extrapolator.extrapolate(stateToUse, target, *propagator);
00434           //dPhiCacheForLoopersReconstruction = fabs(target1.phi()-target2.phi())*2.;
00435           dPhiCacheForLoopersReconstruction = fabs(tmpDphi);
00436           traj.incrementLoops();
00437         }else{
00438           continue;
00439         }
00440       }else{
00441         // ------ For cosmics reconstruction
00442         LogDebug("CkfPattern")<<" self propagating in advanceOneLayer.\n from: \n"<<stateToUse;
00443         //self navigation case
00444         // go to a middle point first
00445         TransverseImpactPointExtrapolator middle;
00446         GlobalPoint center(0,0,0);
00447         stateToUse = middle.extrapolate(stateToUse, center, *theForwardPropagator);
00448         
00449         if (!stateToUse.isValid()) continue;
00450         LogDebug("CkfPattern")<<"to: "<<stateToUse;
00451       }
00452     }
00453     
00454     TrajectorySegmentBuilder layerBuilder(theMeasurementTracker,
00455                                           theLayerMeasurements,
00456                                           **il,*propagator,
00457                                           *theUpdator,*theEstimator,
00458                                           theLockHits,theBestHitOnly);
00459 
00460     LogDebug("CkfPattern")<<whatIsTheStateToUse(stateAndLayers.first,stateToUse,*il);
00461     
00462     TempTrajectoryContainer segments=
00463       layerBuilder.segments(stateToUse);
00464 
00465     LogDebug("CkfPattern")<< "GCTB: number of segments = " << segments.size();
00466 
00467     if ( !segments.empty() )  foundSegments = true;
00468 
00469     for ( TempTrajectoryContainer::const_iterator is=segments.begin();
00470           is!=segments.end(); is++ ) {
00471       //
00472       // assume "invalid hit only" segment is last in list
00473       //
00474       const TempTrajectory::DataContainer & measurements = is->measurements();
00475       if ( !theAlwaysUseInvalid && is!=segments.begin() && measurements.size()==1 && 
00476            (measurements.front().recHit()->getType() == TrackingRecHit::missing) )  break;
00477       //
00478       // create new candidate
00479       //
00480       TempTrajectory newTraj(traj);
00481       traj.setDPhiCacheForLoopersReconstruction(dPhiCacheForLoopersReconstruction);
00482       
00483       //----  avoid to add the same hits more than once in the trajectory ----
00484       bool toBeRejected(false);
00485       for(const TempTrajectory::DataContainer::const_iterator revIt = measurements.rbegin(); 
00486           revIt!=measurements.rend(); --revIt){
00487         int tmpCounter(0);
00488         for(const TempTrajectory::DataContainer::const_iterator newTrajMeasIt = newTraj.measurements().rbegin(); 
00489             newTrajMeasIt != newTraj.measurements().rend(); --newTrajMeasIt){
00490           //if(tmpCounter==2) break;
00491           if(revIt->recHit()->geographicalId()==newTrajMeasIt->recHit()->geographicalId()){
00492             toBeRejected=true;
00493             break;
00494           }
00495           tmpCounter++;
00496         }
00497       }
00498 
00499       if(!toBeRejected){
00500         //newTraj.push(*is);
00501         //std::cout << "DEBUG: newTraj after push found,lost: " 
00502         //        << newTraj.foundHits() << " , " 
00503         //        << newTraj.lostHits() << " , "
00504         //        << newTraj.measurements().size() << std::endl;
00505       }else{    
00506         /*cout << "WARNING: neglect candidate because it contains the same hit twice \n";
00507         cout << "-- discarded track's pt,eta,#found: " 
00508              << newTraj.lastMeasurement().updatedState().globalMomentum().perp() << " , "
00509              << newTraj.lastMeasurement().updatedState().globalMomentum().eta() << " , "
00510              << newTraj.foundHits() << "\n";
00511         */
00512         continue; //Are we sure about this????
00513       }
00514       // ------------------------
00515 
00516 
00517       newTraj.push(*is);
00518       //GIO// for ( vector<TM>::const_iterator im=measurements.begin();
00519       //GIO//        im!=measurements.end(); im++ )  newTraj.push(*im);
00520       //if ( toBeContinued(newTraj,regionalCondition) ) { TOBE FIXED
00521       if ( toBeContinued(newTraj, inOut) ) {
00522         // Have added one more hit to track candidate
00523         
00524         LogDebug("CkfPattern")<<"GCTB: adding updated trajectory to candidates: inOut="<<inOut<<" hits="<<newTraj.foundHits();
00525 
00526         newCand.push_back(newTraj);
00527         foundNewCandidates = true;
00528       }
00529       else {
00530         // Have finished building this track. Check if it passes cuts.
00531 
00532         LogDebug("CkfPattern")<< "GCTB: adding completed trajectory to results if passes cuts: inOut="<<inOut<<" hits="<<newTraj.foundHits();
00533 
00534         addToResult(newTraj, result, inOut);
00535       }
00536     }
00537   }
00538 
00539   if ( !foundSegments ){
00540     LogDebug("CkfPattern")<< "GCTB: adding input trajectory to result";
00541     addToResult(traj, result, inOut);
00542   }
00543   return foundNewCandidates;
00544 }
00545 
00546 //TempTrajectoryContainer
00547 void
00548 GroupedCkfTrajectoryBuilder::groupedIntermediaryClean (TempTrajectoryContainer& theTrajectories) const 
00549 {
00550   //if (theTrajectories.empty()) return TrajectoryContainer();
00551   //TrajectoryContainer result;
00552   if (theTrajectories.empty()) return;  
00553   //RecHitEqualByChannels recHitEqualByChannels(false, false);
00554   int firstLayerSize, secondLayerSize;
00555   vector<const DetLayer*> firstLayers, secondLayers;
00556 
00557   for (TempTrajectoryContainer::iterator firstTraj=theTrajectories.begin();
00558        firstTraj!=(theTrajectories.end()-1); firstTraj++) {
00559 
00560     if ( (!firstTraj->isValid()) ||
00561          (!firstTraj->lastMeasurement().recHit()->isValid()) ) continue;
00562     const TempTrajectory::DataContainer & firstMeasurements = firstTraj->measurements();
00563     layers(firstMeasurements, firstLayers);
00564     firstLayerSize = firstLayers.size();
00565     if ( firstLayerSize<4 )  continue;
00566 
00567     for (TempTrajectoryContainer::iterator secondTraj=(firstTraj+1);
00568        secondTraj!=theTrajectories.end(); secondTraj++) {
00569 
00570       if ( (!secondTraj->isValid()) ||
00571            (!secondTraj->lastMeasurement().recHit()->isValid()) ) continue;
00572       const TempTrajectory::DataContainer & secondMeasurements = secondTraj->measurements();
00573       layers(secondMeasurements, secondLayers);
00574       secondLayerSize = secondLayers.size();
00575       //
00576       // only candidates using the same last 3 layers are compared
00577       //
00578       if ( firstLayerSize!=secondLayerSize )  continue;
00579       if ( firstLayers[0]!=secondLayers[0] ||
00580            firstLayers[1]!=secondLayers[1] ||
00581            firstLayers[2]!=secondLayers[2] )  continue;
00582 
00583       TempTrajectory::DataContainer::const_iterator im1 = firstMeasurements.rbegin();
00584       TempTrajectory::DataContainer::const_iterator im2 = secondMeasurements.rbegin();
00585       //
00586       // check for identical hits in the last layer
00587       //
00588       bool unequal(false);
00589       const DetLayer* layerPtr = firstLayers[0];
00590       while ( im1!=firstMeasurements.rend()&&im2!=secondMeasurements.rend() ) {
00591         if ( im1->layer()!=layerPtr || im2->layer()!=layerPtr )  break;
00592         if ( !(im1->recHit()->isValid()) || !(im2->recHit()->isValid()) ||
00593              !im1->recHit()->hit()->sharesInput(im2->recHit()->hit(), TrackingRecHit::some) ) {
00595           unequal = true;
00596           break;
00597         }
00598         --im1;
00599         --im2;
00600       }
00601       if ( im1==firstMeasurements.rend() || im2==secondMeasurements.rend() ||
00602            im1->layer()==layerPtr || im2->layer()==layerPtr || unequal )  continue;
00603       //
00604       // check for invalid hits in the layer -2
00605       // compare only candidates with invalid / valid combination
00606       //
00607       layerPtr = firstLayers[1];
00608       bool firstValid(true);
00609       while ( im1!=firstMeasurements.rend()&&im1->layer()==layerPtr ) {
00610         if ( !im1->recHit()->isValid() )  firstValid = false;
00611         --im1;
00612       }
00613       bool secondValid(true);
00614       while ( im2!=secondMeasurements.rend()&&im2->layer()==layerPtr ) {
00615         if ( !im2->recHit()->isValid() )  secondValid = false;
00616         --im2;
00617       }
00618       if ( !tkxor(firstValid,secondValid) )  continue;
00619       //
00620       // ask for identical hits in layer -3
00621       //
00622       unequal = false;
00623       layerPtr = firstLayers[2];
00624       while ( im1!=firstMeasurements.rend()&&im2!=secondMeasurements.rend() ) {
00625         if ( im1->layer()!=layerPtr || im2->layer()!=layerPtr )  break;
00626         if ( !(im1->recHit()->isValid()) || !(im2->recHit()->isValid()) ||
00627              !im1->recHit()->hit()->sharesInput(im2->recHit()->hit(), TrackingRecHit::some) ) {
00629           unequal = true;
00630           break;
00631         }
00632         --im1;
00633         --im2;
00634       }
00635       if ( im1==firstMeasurements.rend() || im2==secondMeasurements.rend() ||
00636            im1->layer()==layerPtr || im2->layer()==layerPtr || unequal )  continue;
00637 
00638       if ( !firstValid ) {
00639         firstTraj->invalidate();
00640         break;
00641       }
00642       else {
00643         secondTraj->invalidate();
00644         break;
00645       }
00646     }
00647   }
00648 /*
00649   for (TempTrajectoryContainer::const_iterator it = theTrajectories.begin();
00650        it != theTrajectories.end(); it++) {
00651     if(it->isValid()) result.push_back( *it);
00652   }
00653 
00654   return result;
00655 */
00656   theTrajectories.erase(std::remove_if( theTrajectories.begin(),theTrajectories.end(),
00657                                         std::not1(std::mem_fun_ref(&TempTrajectory::isValid))),
00658  //                                     boost::bind(&TempTrajectory::isValid,_1)), 
00659                         theTrajectories.end());
00660 }
00661 
00662 void
00663 GroupedCkfTrajectoryBuilder::layers (const TempTrajectory::DataContainer& measurements,
00664                                      vector<const DetLayer*> &result) const 
00665 {
00666   result.clear();
00667 
00668   if ( measurements.empty() )  return ;
00669 
00670   result.push_back(measurements.back().layer());
00671   TempTrajectory::DataContainer::const_iterator ifirst = measurements.rbegin();
00672   --ifirst;      
00673   for ( TempTrajectory::DataContainer::const_iterator im=ifirst;
00674         im!=measurements.rend(); --im ) {
00675     if ( im->layer()!=result.back() )  result.push_back(im->layer());
00676   }
00677 
00678   for (vector<const DetLayer*>::const_iterator iter = result.begin(); iter != result.end(); iter++){
00679     if (!*iter) edm::LogWarning("CkfPattern")<< "Warning: null det layer!! ";
00680   }
00681 }
00682 
00683 void
00684 GroupedCkfTrajectoryBuilder::rebuildSeedingRegion(TempTrajectory& startingTraj,
00685                                                   TempTrajectoryContainer& result) const
00686 {
00687   //
00688   // Rebuilding of trajectories. Candidates are taken from result,
00689   // which will be replaced with the solutions after rebuild
00690   // (assume vector::swap is more efficient than building new container)
00691   //
00692   LogDebug("CkfPattern")<< "Starting to rebuild " << result.size() << " tracks";
00693   //
00694   // Fitter (need to create it here since the propagation direction
00695   // might change between different starting trajectories)
00696   //
00697   KFTrajectoryFitter fitter(&(*theBackwardPropagator),&updator(),&estimator());
00698   //
00699   TempTrajectoryContainer reFitted;
00700   TrajectorySeed::range rseedHits = startingTraj.seed().recHits();
00701   std::vector<const TrackingRecHit*> seedHits;
00702   //seedHits.insert(seedHits.end(), rseedHits.first, rseedHits.second);
00703   //for (TrajectorySeed::recHitContainer::const_iterator iter = rseedHits.first; iter != rseedHits.second; iter++){
00704   //    seedHits.push_back(&*iter);
00705   //}
00706 
00707   //unsigned int nSeed(seedHits.size());
00708   unsigned int nSeed(rseedHits.second-rseedHits.first);
00709   //seedHits.reserve(nSeed);
00710   TempTrajectoryContainer rebuiltTrajectories;
00711   for ( TempTrajectoryContainer::iterator it=result.begin();
00712         it!=result.end(); it++ ) {
00713     //
00714     // skip candidates which are not exceeding the seed size 
00715     // (e.g. because no Tracker layers outside seeding region) 
00716     //
00717 
00718     if ( it->measurements().size()<=startingTraj.measurements().size() ) {
00719       rebuiltTrajectories.push_back(*it);
00720       LogDebug("CkfPattern")<< "RebuildSeedingRegion skipped as in-out trajectory does not exceed seed size.";
00721       continue;
00722     }
00723     //
00724     // Refit - keep existing trajectory in case fit is not possible
00725     // or fails
00726     //
00727 
00728     backwardFit(*it,nSeed,fitter,reFitted,seedHits);
00729     if ( reFitted.size()!=1 ) {
00730       rebuiltTrajectories.push_back(*it);
00731       LogDebug("CkfPattern")<< "RebuildSeedingRegion skipped as backward fit failed";
00732       //                            << "after reFitted.size() " << reFitted.size();
00733       continue;
00734     }
00735     //LogDebug("CkfPattern")<<"after reFitted.size() " << reFitted.size();
00736     //
00737     // Rebuild seeding part. In case it fails: keep initial trajectory
00738     // (better to drop it??)
00739     //
00740     int nRebuilt =
00741       rebuildSeedingRegion (seedHits,reFitted.front(),rebuiltTrajectories);
00742 
00743     if ( nRebuilt==0 ) it->invalidate();  // won't use original in-out track
00744 
00745     if ( nRebuilt<=0 ) rebuiltTrajectories.push_back(*it);
00746 
00747   }
00748   //
00749   // Replace input trajectories with new ones
00750   //
00751   result.swap(rebuiltTrajectories);
00752   result.erase(std::remove_if( result.begin(),result.end(),
00753                                std::not1(std::mem_fun_ref(&TempTrajectory::isValid))),
00754                result.end());
00755 }
00756 
00757 int
00758 GroupedCkfTrajectoryBuilder::rebuildSeedingRegion(const std::vector<const TrackingRecHit*>& seedHits, 
00759                                                   TempTrajectory& candidate,
00760                                                   TempTrajectoryContainer& result) const 
00761 {
00762   //
00763   // Starting from track found by in-out tracking phase, extrapolate it inwards through
00764   // the seeding region if possible in towards smaller Tracker radii, searching for additional
00765   // hits.
00766   // The resulting trajectories are returned in result,
00767   // the count is the return value.
00768   //
00769   TempTrajectoryContainer rebuiltTrajectories;
00770 #ifdef DBG2_GCTB
00771 /*  const LayerFinderByDet layerFinder;
00772   if ( !seedHits.empty() && seedHits.front().isValid() ) {
00773     DetLayer* seedLayer = layerFinder(seedHits.front().det());
00774     cout << "Seed hit at " << seedHits.front().globalPosition()
00775          << " " << seedLayer << endl;
00776     cout << "Started from " 
00777          << candidate.lastMeasurement().updatedState().globalPosition().perp() << " "
00778          << candidate.lastMeasurement().updatedState().globalPosition().z() << endl;
00779     pair<bool,TrajectoryStateOnSurface> layerComp(false,TrajectoryStateOnSurface());
00780     if ( seedLayer ) layerComp =
00781       seedLayer->compatible(candidate.lastMeasurement().updatedState(),
00782                               propagator(),estimator());
00783     pair<bool,TrajectoryStateOnSurface> detComp =
00784       seedHits.front().det().compatible(candidate.lastMeasurement().updatedState(),
00785                                         propagator(),estimator());
00786     cout << "  layer compatibility = " << layerComp.first;
00787     cout << "  det compatibility = " << detComp.first;
00788     if ( detComp.first ) {
00789       cout << "  estimate = " 
00790            << estimator().estimate(detComp.second,seedHits.front()).second ;
00791     }
00792     cout << endl;
00793   }*/
00794   cout << "Before backward building: #measurements = " 
00795        << candidate.measurements().size() ; //<< endl;;
00796 #endif
00797   //
00798   // Use standard building with standard cuts. Maybe better to use different
00799   // cuts from "forward" building (e.g. no check on nr. of invalid hits)?
00800   //
00801   const bool inOut = false;
00802   groupedLimitedCandidates(candidate, (const TrajectoryFilter*)0, theBackwardPropagator, inOut, rebuiltTrajectories);
00803 
00804   LogDebug("CkfPattern")<<" After backward building: "<<PrintoutHelper::dumpCandidates(rebuiltTrajectories);
00805 
00806   //
00807   // Check & count resulting candidates
00808   //
00809   int nrOfTrajectories(0);
00810   bool orig_ok = false;
00811   //const RecHitEqualByChannels recHitEqual(false,false);
00812   //vector<TM> oldMeasurements(candidate.measurements());
00813   for ( TempTrajectoryContainer::iterator it=rebuiltTrajectories.begin();
00814         it!=rebuiltTrajectories.end(); it++ ) {
00815 
00816     TempTrajectory::DataContainer newMeasurements(it->measurements());
00817     //
00818     // Verify presence of seeding hits?
00819     //
00820     if ( theRequireSeedHitsInRebuild ) {
00821       orig_ok = true;
00822       // no hits found (and possibly some invalid hits discarded): drop track
00823       if ( newMeasurements.size()<=candidate.measurements().size() ){  
00824         LogDebug("CkfPattern") << "newMeasurements.size()<=candidate.measurements().size()";
00825         continue;
00826       } 
00827       // verify presence of hits
00828       //GIO//if ( !verifyHits(newMeasurements.begin()+candidate.measurements().size(),
00829       //GIO//                  newMeasurements.end(),seedHits) ){
00830       if ( !verifyHits(newMeasurements.rbegin(), 
00831                        newMeasurements.size() - candidate.measurements().size(),
00832                        seedHits) ){
00833         LogDebug("CkfPattern")<< "seed hits not found in rebuild";
00834         continue; 
00835       }
00836     }
00837     //
00838     // construct final trajectory in the right order
00839     //
00840     TempTrajectory reversedTrajectory(it->seed(),it->seed().direction());
00841     reversedTrajectory.setNLoops(it->nLoops());
00842     for (TempTrajectory::DataContainer::const_iterator im=newMeasurements.rbegin(), ed = newMeasurements.rend();
00843           im != ed; --im ) {
00844       reversedTrajectory.push(*im);
00845     }
00846     // save & count result
00847     result.push_back(reversedTrajectory);
00848     nrOfTrajectories++;
00849 
00850     LogDebug("CkgPattern")<<"New traj direction = " << reversedTrajectory.direction()<<"\n"
00851                           <<PrintoutHelper::dumpMeasurements(reversedTrajectory.measurements());
00852   }
00853   // If nrOfTrajectories = 0 and orig_ok = true, this means that a track was actually found on the
00854   // out-in step (meeting those requirements) but did not have the seed hits in it.
00855   // In this case when we return we will go ahead and use the original in-out track.
00856 
00857   // If nrOfTrajectories = 0 and orig_ok = false, this means that the out-in step failed to
00858   // find any track.  Two cases are a technical failure in fitting the original seed hits or
00859   // because the track did not meet the out-in criteria (which may be stronger than the out-in
00860   // criteria).  In this case we will NOT allow the original in-out track to be used.
00861 
00862   if ( (nrOfTrajectories == 0) && orig_ok ) {
00863     nrOfTrajectories = -1;
00864   }
00865   return nrOfTrajectories;
00866 }
00867 
00868 void
00869 GroupedCkfTrajectoryBuilder::backwardFit (TempTrajectory& candidate, unsigned int nSeed,
00870                                           const TrajectoryFitter& fitter,
00871                                           TempTrajectoryContainer& fittedTracks,
00872                                           std::vector<const TrackingRecHit*>& remainingHits) const
00873 {
00874   //
00875   // clear array of non-fitted hits
00876   //
00877   remainingHits.clear();
00878   fittedTracks.clear();
00879   //
00880   // skip candidates which are not exceeding the seed size
00881   // (e.g. Because no Tracker layers exist outside seeding region)
00882   //
00883   if ( candidate.measurements().size()<=nSeed ) {
00884     fittedTracks.clear();
00885     return;
00886   }
00887 
00888   LogDebug("CkfPattern")<<"nSeed " << nSeed << endl
00889                         << "Old traj direction = " << candidate.direction() << endl
00890                         <<PrintoutHelper::dumpMeasurements(candidate.measurements());
00891 
00892   //
00893   // backward fit trajectory.
00894   // (Will try to fit only hits outside the seeding region. However,
00895   // if there are not enough of these, it will also use the seeding hits).
00896   //
00897   TempTrajectory::DataContainer oldMeasurements(candidate.measurements());
00898 //   int nOld(oldMeasurements.size());
00899 //   const unsigned int nHitAllMin(5);
00900 //   const unsigned int nHit2dMin(2);
00901   unsigned int nHit(0);    // number of valid hits after seeding region
00902   //unsigned int nHit2d(0);  // number of valid hits after seeding region with 2D info
00903   // use all hits except the first n (from seed), but require minimum
00904   // specified in configuration.
00905   //  Swapped over next two lines.
00906   unsigned int nHitMin = max(candidate.foundHits()-nSeed,theMinNrOfHitsForRebuild);
00907   //  unsigned int nHitMin = oldMeasurements.size()-nSeed;
00908   // we want to rebuild only if the number of VALID measurements excluding the seed measurements is higher than the cut
00909   if (nHitMin<theMinNrOfHitsForRebuild){
00910         fittedTracks.clear();
00911         return;
00912   }
00913 
00914   LogDebug("CkfPattern")/* << "nHitMin " << nHitMin*/ <<"Sizes: " << oldMeasurements.size() << " / ";
00915   //
00916   // create input trajectory for backward fit
00917   //
00918   Trajectory fwdTraj(candidate.seed(),oppositeDirection(candidate.direction()));
00919   fwdTraj.setNLoops(candidate.nLoops());
00920   //const TrajectorySeed seed = TrajectorySeed(PTrajectoryStateOnDet(), TrajectorySeed::recHitContainer(), oppositeDirection(candidate.direction()));
00921   //Trajectory fwdTraj(seed, oppositeDirection(candidate.direction()));
00922   std::vector<const DetLayer*> bwdDetLayer; 
00923   for ( TempTrajectory::DataContainer::const_iterator im=oldMeasurements.rbegin();
00924         im!=oldMeasurements.rend(); --im) {
00925     const TrackingRecHit* hit = im->recHit()->hit();
00926     //
00927     // add hits until required number is reached
00928     //
00929     if ( nHit<nHitMin ){//|| nHit2d<theMinNrOf2dHitsForRebuild ) {
00930       fwdTraj.push(*im);
00931       bwdDetLayer.push_back(im->layer());
00932       //
00933       // count valid / 2D hits
00934       //
00935       if ( hit->isValid() ) {
00936         nHit++;
00937         //if ( hit.isMatched() ||
00938         //     hit.det().detUnits().front()->type().module()==pixel )
00939         //nHit2d++;
00940       }
00941     }
00942     //if (nHit==nHitMin) lastBwdDetLayer=im->layer();   
00943     //
00944     // keep remaining (valid) hits for verification
00945     //
00946     else if ( hit->isValid() ) {
00947       //std::cout << "Adding a remaining hit" << std::endl;
00948       remainingHits.push_back(hit);
00949     }
00950   }
00951   //
00952   // Fit only if required number of valid hits can be used
00953   //
00954   if ( nHit<nHitMin ){  //|| nHit2d<theMinNrOf2dHitsForRebuild ) {
00955     fittedTracks.clear();
00956     return;
00957   }
00958   //
00959   // Do the backward fit (important: start from scaled, not random cov. matrix!)
00960   //
00961   TrajectoryStateOnSurface firstTsos(fwdTraj.firstMeasurement().updatedState());
00962   //cout << "firstTsos "<< firstTsos << endl;
00963   firstTsos.rescaleError(10.);
00964   //TrajectoryContainer bwdFitted(fitter.fit(fwdTraj.seed(),fwdTraj.recHits(),firstTsos));
00965   TrajectoryContainer bwdFitted(fitter.fit(
00966                 TrajectorySeed(PTrajectoryStateOnDet(), TrajectorySeed::recHitContainer(), oppositeDirection(candidate.direction())),
00967                 fwdTraj.recHits(),firstTsos));
00968   if (bwdFitted.size()){
00969     LogDebug("CkfPattern")<<"Obtained " << bwdFitted.size() << " bwdFitted trajectories with measurement size " << bwdFitted.front().measurements().size();
00970         TempTrajectory fitted(fwdTraj.seed(), fwdTraj.direction());
00971         fitted.setNLoops(fwdTraj.nLoops());
00972         vector<TM> tmsbf = bwdFitted.front().measurements();
00973         int iDetLayer=0;
00974         //this is ugly but the TM in the fitted track do not contain the DetLayer.
00975         //So we have to cache the detLayer pointers and replug them in.
00976         //For the backward building it would be enaugh to cache the last DetLayer, 
00977         //but for the intermediary cleaning we need all
00978         for ( vector<TM>::const_iterator im=tmsbf.begin();im!=tmsbf.end(); im++ ) {
00979                 fitted.push(TM( (*im).forwardPredictedState(),
00980                                 (*im).backwardPredictedState(),
00981                                 (*im).updatedState(),
00982                                 (*im).recHit(),
00983                                 (*im).estimate(),
00984                                 bwdDetLayer[iDetLayer]));
00985 
00986                 LogDebug("CkfPattern")<<PrintoutHelper::dumpMeasurement(*im);
00987                 iDetLayer++;
00988         }
00989 /*
00990         TM lastMeas = bwdFitted.front().lastMeasurement();
00991         fitted.pop();
00992         fitted.push(TM(lastMeas.forwardPredictedState(), 
00993                                lastMeas.backwardPredictedState(), 
00994                                lastMeas.updatedState(),
00995                                lastMeas.recHit(),
00996                                lastMeas.estimate(),
00997                                lastBwdDetLayer));*/
00998         fittedTracks.push_back(fitted);
00999   }
01000   //
01001   // save result
01002   //
01003   //fittedTracks.swap(bwdFitted);
01004   //cout << "Obtained " << fittedTracks.size() << " fittedTracks trajectories with measurement size " << fittedTracks.front().measurements().size() << endl;
01005 }
01006 
01007 bool
01008 GroupedCkfTrajectoryBuilder::verifyHits (TempTrajectory::DataContainer::const_iterator rbegin,
01009                                          size_t maxDepth,
01010                                          const std::vector<const TrackingRecHit*>& hits) const
01011 {
01012   //
01013   // verify presence of the seeding hits
01014   //
01015   LogDebug("CkfPattern")<<"Checking for " << hits.size() << " hits in "
01016                         << maxDepth << " measurements" << endl;
01017 
01018   TempTrajectory::DataContainer::const_iterator rend = rbegin; 
01019   while (maxDepth > 0) { --maxDepth; --rend; }
01020   for ( vector<const TrackingRecHit*>::const_iterator ir=hits.begin();
01021         ir!=hits.end(); ir++ ) {
01022     // assume that all seeding hits are valid!
01023     bool foundHit(false);
01024     for ( TempTrajectory::DataContainer::const_iterator im=rbegin; im!=rend; --im ) {
01025       if ( im->recHit()->isValid() && (*ir)->sharesInput(im->recHit()->hit(), TrackingRecHit::some) ) {
01026         foundHit = true;
01027         break;
01028       }
01029     }
01030     if ( !foundHit )  return false;
01031   }
01032   return true;
01033 }
01034 
01035 
01036 
01037