00001 #include "RecoParticleFlow/PFProducer/interface/PFBlockAlgo.h"
00002 #include "RecoParticleFlow/PFProducer/interface/Utils.h"
00003 #include "RecoParticleFlow/PFClusterTools/interface/LinkByRecHit.h"
00004 #include "DataFormats/ParticleFlowReco/interface/PFBlock.h"
00005 #include "DataFormats/TrackReco/interface/Track.h"
00006 #include "DataFormats/ParticleFlowReco/interface/PFDisplacedVertex.h"
00007
00008 #include "DataFormats/ParticleFlowReco/interface/PFRecHit.h"
00009
00010 #include <stdexcept>
00011 #include "TMath.h"
00012
00013 using namespace std;
00014 using namespace reco;
00015
00016
00017
00018
00019 const PFBlockAlgo::Mask PFBlockAlgo::dummyMask_;
00020
00021 PFBlockAlgo::PFBlockAlgo() :
00022 blocks_( new reco::PFBlockCollection ),
00023 DPtovPtCut_(std::vector<double>(4,static_cast<double>(999.))),
00024 NHitCut_(std::vector<unsigned int>(4,static_cast<unsigned>(0))),
00025 useIterTracking_(true),
00026 photonSelector_(0),
00027 debug_(false) {}
00028
00029
00030
00031 void PFBlockAlgo::setParameters( std::vector<double>& DPtovPtCut,
00032 std::vector<unsigned int>& NHitCut,
00033 bool useConvBremPFRecTracks,
00034 bool useIterTracking,
00035 int nuclearInteractionsPurity,
00036 bool useEGPhotons,
00037 std::vector<double>& photonSelectionCuts) {
00038
00039 DPtovPtCut_ = DPtovPtCut;
00040 NHitCut_ = NHitCut;
00041 useIterTracking_ = useIterTracking;
00042 useConvBremPFRecTracks_ = useConvBremPFRecTracks;
00043 nuclearInteractionsPurity_ = nuclearInteractionsPurity;
00044 useEGPhotons_ = useEGPhotons;
00045
00046 if(useEGPhotons_)
00047 photonSelector_ = new PhotonSelectorAlgo(photonSelectionCuts[0],
00048 photonSelectionCuts[1], photonSelectionCuts[2],
00049 photonSelectionCuts[3], photonSelectionCuts[4],
00050 photonSelectionCuts[5], photonSelectionCuts[6],
00051 photonSelectionCuts[7],
00052 photonSelectionCuts[8],
00053 photonSelectionCuts[9],
00054 photonSelectionCuts[10]
00055 );
00056
00057
00058 }
00059
00060
00061 void PFBlockAlgo::setUseOptimization(bool useKDTreeTrackEcalLinker)
00062 {
00063 useKDTreeTrackEcalLinker_ = useKDTreeTrackEcalLinker;
00064 }
00065
00066
00067
00068 PFBlockAlgo::~PFBlockAlgo() {
00069
00070 #ifdef PFLOW_DEBUG
00071 if(debug_)
00072 cout<<"~PFBlockAlgo - number of remaining elements: "
00073 <<elements_.size()<<endl;
00074 #endif
00075
00076 if(photonSelector_) delete photonSelector_;
00077
00078 }
00079
00080 void
00081 PFBlockAlgo::findBlocks() {
00082
00083
00084 if (useKDTreeTrackEcalLinker_) {
00085 TELinker_.process();
00086 THLinker_.process();
00087 PSELinker_.process();
00088 }
00089
00090
00091
00092 if(blocks_.get() )blocks_->clear();
00093 else
00094 blocks_.reset( new reco::PFBlockCollection );
00095
00096 blocks_->reserve(elements_.size());
00097 for(IE ie = elements_.begin();
00098 ie != elements_.end();) {
00099
00100 #ifdef PFLOW_DEBUG
00101 if(debug_) {
00102 cout<<" PFBlockAlgo::findBlocks() ----------------------"<<endl;
00103 cout<<" element "<<**ie<<endl;
00104 cout<<" creating new block"<<endl;
00105 }
00106 #endif
00107
00108 blocks_->push_back( PFBlock() );
00109
00110 vector< PFBlockLink > links;
00111
00112
00113 ie = associate( elements_.end() , ie, links );
00114
00115 packLinks( blocks_->back(), links );
00116 }
00117 }
00118
00119
00120
00121
00122 PFBlockAlgo::IE
00123 PFBlockAlgo::associate( IE last,
00124 IE next,
00125 vector<PFBlockLink>& links ) {
00126
00127
00128 #ifdef PFLOW_DEBUG
00129 if(debug_ ) cout<<"PFBlockAlgo::associate start ----"<<endl;
00130 #endif
00131
00132 if( last!= elements_.end() ) {
00133 PFBlockLink::Type linktype = PFBlockLink::NONE;
00134 double dist = -1;
00135 PFBlock::LinkTest linktest = PFBlock::LINKTEST_RECHIT;
00136 link( *last, *next, linktype, linktest, dist );
00137
00138
00139 if(dist<-0.5) {
00140 #ifdef PFLOW_DEBUG
00141 if(debug_ ) cout<<"link failed"<<endl;
00142 #endif
00143 return ++next;
00144 }
00145 else {
00146
00147 blocks_->back().addElement( *next );
00148
00149
00150
00151
00152
00153
00154
00155 links.push_back( PFBlockLink(linktype,
00156 linktest,
00157 dist,
00158 (*last)->index(),
00159 (*next)->index() ) );
00160
00161
00162
00163 }
00164 }
00165 else {
00166
00167 #ifdef PFLOW_DEBUG
00168 if(debug_ ) cout<<"adding to block element "<<(**next)<<endl;
00169 #endif
00170 blocks_->back().addElement( *next );
00171
00172
00173 }
00174
00175
00176
00177
00178
00179
00180
00181 for(IE ie = elements_.begin();
00182 ie != elements_.end();) {
00183
00184 if( ie == last || ie == next ) {
00185 ++ie;
00186 continue;
00187 }
00188 bool bTestLink = linkPrefilter(*next, *ie);
00189
00190 if(!bTestLink) {
00191 ++ie;
00192 continue;
00193 }
00194
00195
00196 if( (*ie)->locked() ) {
00197 #ifdef PFLOW_DEBUG
00198 if(debug_ ) cout<<"element "<<(**ie)<<"already used"<<endl;
00199 #endif
00200 ++ie;
00201 continue;
00202 }
00203
00204
00205 #ifdef PFLOW_DEBUG
00206 if(debug_ ) cout<<"calling associate "<<(**next)<<" & "<<(**ie)<<endl;
00207 #endif
00208 ie = associate(next, ie, links);
00209 }
00210
00211 #ifdef PFLOW_DEBUG
00212 if(debug_ ) {
00213 cout<<"**** deleting element "<<endl;
00214 cout<<**next<<endl;
00215 }
00216 #endif
00217 delete *next;
00218
00219 #ifdef PFLOW_DEBUG
00220 if(debug_ ) {
00221 cout<<"**** removing element "<<endl;
00222 }
00223 #endif
00224
00225 IE iteratorToNextFreeElement = elements_.erase( next );
00226
00227 #ifdef PFLOW_DEBUG
00228 if(debug_ ) cout<<"PFBlockAlgo::associate stop ----"<<endl;
00229 #endif
00230
00231 return iteratorToNextFreeElement;
00232 }
00233
00234
00235
00236 void
00237 PFBlockAlgo::packLinks( reco::PFBlock& block,
00238 const vector<PFBlockLink>& links ) const {
00239
00240
00241 const edm::OwnVector< reco::PFBlockElement >& els = block.elements();
00242
00243 block.bookLinkData();
00244
00245 unsigned elsize = els.size();
00246 unsigned ilStart = 0;
00247
00248 for( unsigned i1=0; i1<elsize; ++i1 ) {
00249 for( unsigned i2=0; i2<i1; ++i2 ) {
00250
00251
00252
00253
00254 double dist = -1;
00255
00256 bool linked = false;
00257 PFBlock::LinkTest linktest
00258 = PFBlock::LINKTEST_RECHIT;
00259
00260
00261
00262
00263 unsigned linksize = links.size();
00264 for( unsigned il = ilStart; il<linksize; ++il ) {
00265
00266 if ( links[il].element2() < i1 ) ilStart = il;
00267 if ( links[il].element2() > i1 ) break;
00268 if( (links[il].element1() == i2 &&
00269 links[il].element2() == i1) ) {
00270
00271 dist = links[il].dist();
00272 linked = true;
00273
00274
00275
00276 linktest = links[il].test();
00277 #ifdef PFLOW_DEBUG
00278 if( debug_ )
00279 cout << "Reading link vector: linktest used="
00280 << linktest
00281 << " distance = " << dist
00282 << endl;
00283 #endif
00284
00285
00286 break;
00287 }
00288 }
00289
00290 if(!linked) {
00291 PFBlockLink::Type linktype = PFBlockLink::NONE;
00292 bool bTestLink = linkPrefilter(&els[i1], &els[i2]);
00293 if (bTestLink) link( & els[i1], & els[i2], linktype, linktest, dist);
00294 }
00295
00296
00297
00298 #ifdef PFLOW_DEBUG
00299 if( debug_ )
00300 cout << "Setting link between elements " << i1 << " and " << i2
00301 << " of dist =" << dist << " computed from link test "
00302 << linktest << endl;
00303 #endif
00304 block.setLink( i1, i2, dist, block.linkData(), linktest );
00305 }
00306 }
00307
00308 }
00309
00310
00311
00312 void
00313 PFBlockAlgo::buildGraph() {
00314
00315 }
00316
00317
00318
00319 void
00320 PFBlockAlgo::link( const reco::PFBlockElement* el1,
00321 const reco::PFBlockElement* el2,
00322 PFBlockLink::Type& linktype,
00323 reco::PFBlock::LinkTest& linktest,
00324 double& dist) const {
00325
00326
00327
00328
00329 dist=-1.;
00330 linktest = PFBlock::LINKTEST_RECHIT;
00331
00332 PFBlockElement::Type type1 = el1->type();
00333 PFBlockElement::Type type2 = el2->type();
00334
00335 linktype = static_cast<PFBlockLink::Type>
00336 ((1<< (type1-1) ) | (1<< (type2-1) ));
00337
00338 if(debug_ ) std::cout << " PFBlockAlgo links type1 " << type1 << " type2 " << type2 << std::endl;
00339
00340 const PFBlockElement* lowEl = el1;
00341 const PFBlockElement* highEl = el2;
00342
00343 if(type1>type2) {
00344 lowEl = el2;
00345 highEl = el1;
00346 }
00347
00348 switch(linktype) {
00349
00350 case PFBlockLink::PS1andECAL:
00351 case PFBlockLink::PS2andECAL:
00352 {
00353
00354 PFClusterRef psref = lowEl->clusterRef();
00355 PFClusterRef ecalref = highEl->clusterRef();
00356 assert( !psref.isNull() );
00357 assert( !ecalref.isNull() );
00358
00359
00360
00361 if ( useKDTreeTrackEcalLinker_ && lowEl->isMultilinksValide() ) {
00362 const reco::PFMultilinksType& multilinks = lowEl->getMultilinks();
00363
00364 double ecalPhi = ecalref->positionREP().Phi();
00365 double ecalEta = ecalref->positionREP().Eta();
00366
00367
00368 reco::PFMultilinksType::const_iterator mlit = multilinks.begin();
00369 for (; mlit != multilinks.end(); ++mlit)
00370 if ((mlit->first == ecalPhi) && (mlit->second == ecalEta))
00371 break;
00372
00373
00374 if (mlit != multilinks.end()){
00375 double xPS = psref->position().X();
00376 double yPS = psref->position().Y();
00377 double xECAL = ecalref->position().X();
00378 double yECAL = ecalref->position().Y();
00379
00380 dist = LinkByRecHit::computeDist(xECAL/1000.,yECAL/1000.,xPS/1000. ,yPS/1000, false);
00381 }
00382
00383 } else {
00384 dist = LinkByRecHit::testECALAndPSByRecHit( *ecalref, *psref ,debug_);
00385 }
00386
00387
00388
00389 break;
00390 }
00391 case PFBlockLink::TRACKandECAL:
00392 {
00393 if(debug_ ) cout<<"TRACKandECAL"<<endl;
00394
00395 PFRecTrackRef trackref = lowEl->trackRefPF();
00396 PFClusterRef clusterref = highEl->clusterRef();
00397 assert( !trackref.isNull() );
00398 assert( !clusterref.isNull() );
00399
00400 if(debug_ ) std::cout << " Track pt " << trackref->trackRef()->pt() << std::endl;
00401
00402
00403
00404 if ( useKDTreeTrackEcalLinker_ && lowEl->isMultilinksValide() ) {
00405
00406 const reco::PFMultilinksType& multilinks = lowEl->getMultilinks();
00407 double ecalphi = clusterref->positionREP().Phi();
00408 double ecaleta = clusterref->positionREP().Eta();
00409
00410
00411 reco::PFMultilinksType::const_iterator mlit = multilinks.begin();
00412 for (; mlit != multilinks.end(); ++mlit)
00413 if ((mlit->first == ecalphi) && (mlit->second == ecaleta))
00414 break;
00415
00416
00417
00418 if (mlit != multilinks.end()){
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 const reco::PFTrajectoryPoint& atECAL =
00435 trackref->extrapolatedPoint( reco::PFTrajectoryPoint::ECALShowerMax );
00436
00437 double tracketa = atECAL.positionREP().Eta();
00438 double trackphi = atECAL.positionREP().Phi();
00439
00440 dist = LinkByRecHit::computeDist(ecaleta, ecalphi, tracketa, trackphi);
00441 }
00442
00443 } else {
00444 if ( trackref->extrapolatedPoint( reco::PFTrajectoryPoint::ECALShowerMax ).isValid() )
00445 dist = LinkByRecHit::testTrackAndClusterByRecHit( *trackref, *clusterref, false, debug_ );
00446 else
00447 dist = -1.;
00448 }
00449
00450 if ( debug_ ) {
00451 if( dist > 0. ) {
00452 std::cout << " Here a link has been established"
00453 << " between a track an Ecal with dist "
00454 << dist << std::endl;
00455 } else
00456 std::cout << " No link found " << std::endl;
00457 }
00458
00459
00460 break;
00461 }
00462 case PFBlockLink::TRACKandHCAL:
00463 {
00464
00465
00466 PFRecTrackRef trackref = lowEl->trackRefPF();
00467 PFClusterRef clusterref = highEl->clusterRef();
00468 assert( !trackref.isNull() );
00469 assert( !clusterref.isNull() );
00470
00471
00472
00473 if ( useKDTreeTrackEcalLinker_ && highEl->isMultilinksValide() ) {
00474
00475 const reco::PFMultilinksType& multilinks = highEl->getMultilinks();
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 const reco::PFTrajectoryPoint& atHCAL =
00488 trackref->extrapolatedPoint(reco::PFTrajectoryPoint::HCALEntrance);
00489
00490
00491 double tracketa = atHCAL.positionREP().Eta();
00492 double trackphi = atHCAL.positionREP().Phi();
00493
00494
00495 reco::PFMultilinksType::const_iterator mlit = multilinks.begin();
00496 for (; mlit != multilinks.end(); ++mlit)
00497 if ((mlit->first == trackphi) && (mlit->second == tracketa))
00498 break;
00499
00500
00501 if (mlit != multilinks.end()){
00502
00503 const reco::PFTrajectoryPoint& atHCALExit =
00504 trackref->extrapolatedPoint(reco::PFTrajectoryPoint::HCALExit);
00505 double dHEta = 0.0;
00506 double dHPhi = 0.0;
00507 if (atHCALExit.position().R()>atHCAL.position().R()) {
00508 dHEta = atHCALExit.positionREP().Eta()-atHCAL.positionREP().Eta();
00509 dHPhi = atHCALExit.positionREP().Phi()-atHCAL.positionREP().Phi();
00510 if ( dHPhi > M_PI ) dHPhi = dHPhi - 2.*M_PI;
00511 else if ( dHPhi < -M_PI ) dHPhi = dHPhi + 2.*M_PI;
00512 } else {
00513 std::cout << "Qu'est ce que c'est que ce gag ? "
00514 << atHCALExit.position().R() << " is larger than "
00515 << atHCAL.position().R() << " !" << std::endl;
00516 }
00517
00518 tracketa += 0.1 * dHEta;
00519 trackphi += 0.1 * dHPhi;
00520
00521 double clusterphi = clusterref->positionREP().Phi();
00522 double clustereta = clusterref->positionREP().Eta();
00523
00524 dist = LinkByRecHit::computeDist(clustereta, clusterphi, tracketa, trackphi);
00525 }
00526
00527 } else {
00528 if ( trackref->extrapolatedPoint( reco::PFTrajectoryPoint::HCALEntrance ).isValid() )
00529 dist = LinkByRecHit::testTrackAndClusterByRecHit( *trackref, *clusterref, false, debug_ );
00530 else
00531 dist = -1.;
00532 }
00533
00534
00535 break;
00536 }
00537 case PFBlockLink::TRACKandHO:
00538 {
00539 if(debug_ ) cout<<"TRACKandHO"<<endl;
00540
00541 PFRecTrackRef trackref = lowEl->trackRefPF();
00542 PFClusterRef clusterref = highEl->clusterRef();
00543
00544 assert( !trackref.isNull() );
00545 assert( !clusterref.isNull() );
00546
00547
00548
00549
00550
00551 if ( lowEl->trackRef()->pt() > 3.00001 && trackref->extrapolatedPoint( reco::PFTrajectoryPoint::HOLayer ).isValid() ) {
00552
00553 dist = LinkByRecHit::testTrackAndClusterByRecHit( *trackref, *clusterref, false, debug_ );
00554
00555
00556 } else {
00557 dist = -1.;
00558 }
00559
00560 break;
00561 }
00562 case PFBlockLink::ECALandHCAL:
00563 {
00564
00565 PFClusterRef ecalref = lowEl->clusterRef();
00566 PFClusterRef hcalref = highEl->clusterRef();
00567 assert( !ecalref.isNull() );
00568 assert( !hcalref.isNull() );
00569
00570 dist = testECALAndHCAL( *ecalref, *hcalref );
00571
00572
00573 break;
00574 }
00575 case PFBlockLink::HCALandHO:
00576 {
00577
00578 PFClusterRef hcalref = lowEl->clusterRef();
00579 PFClusterRef horef = highEl->clusterRef();
00580 assert( !hcalref.isNull() );
00581 assert( !horef.isNull() );
00582
00583 dist = testHCALAndHO( *hcalref, *horef );
00584
00585
00586
00587 break;
00588 }
00589 case PFBlockLink::HFEMandHFHAD:
00590 {
00591
00592 PFClusterRef eref = lowEl->clusterRef();
00593 PFClusterRef href = highEl->clusterRef();
00594 assert( !eref.isNull() );
00595 assert( !href.isNull() );
00596 dist = LinkByRecHit::testHFEMAndHFHADByRecHit( *eref, *href, debug_ );
00597
00598 break;
00599 }
00600
00601 case PFBlockLink::TRACKandTRACK:
00602 {
00603 if(debug_ )
00604 cout<<"TRACKandTRACK"<<endl;
00605 dist = testLinkByVertex(lowEl, highEl);
00606 if(debug_ )
00607 std::cout << " PFBlockLink::TRACKandTRACK dist " << dist << std::endl;
00608
00609 break;
00610 }
00611
00612 case PFBlockLink::ECALandECAL:
00613 {
00614
00615 PFClusterRef ecal1ref = lowEl->clusterRef();
00616 PFClusterRef ecal2ref = highEl->clusterRef();
00617 assert( !ecal1ref.isNull() );
00618 assert( !ecal2ref.isNull() );
00619 if(debug_)
00620 cout << " PFBlockLink::ECALandECAL" << endl;
00621 dist = testLinkBySuperCluster(ecal1ref,ecal2ref);
00622 break;
00623 }
00624
00625 case PFBlockLink::ECALandGSF:
00626 {
00627 PFClusterRef clusterref = lowEl->clusterRef();
00628 assert( !clusterref.isNull() );
00629 const reco::PFBlockElementGsfTrack * GsfEl = dynamic_cast<const reco::PFBlockElementGsfTrack*>(highEl);
00630 const PFRecTrack * myTrack = &(GsfEl->GsftrackPF());
00631 if ( myTrack->extrapolatedPoint( reco::PFTrajectoryPoint::ECALShowerMax ).isValid() )
00632 dist = LinkByRecHit::testTrackAndClusterByRecHit( *myTrack, *clusterref, false, debug_ );
00633 else
00634 dist = -1.;
00635
00636
00637 if ( debug_ ) {
00638 if ( dist > 0. ) {
00639 std::cout << " Here a link has been established"
00640 << " between a GSF track an Ecal with dist "
00641 << dist << std::endl;
00642 } else {
00643 if(debug_ ) std::cout << " No link found " << std::endl;
00644 }
00645 }
00646 break;
00647 }
00648 case PFBlockLink::TRACKandGSF:
00649 {
00650 PFRecTrackRef trackref = lowEl->trackRefPF();
00651 assert( !trackref.isNull() );
00652 const reco::PFBlockElementGsfTrack * GsfEl =
00653 dynamic_cast<const reco::PFBlockElementGsfTrack*>(highEl);
00654 GsfPFRecTrackRef gsfref = GsfEl->GsftrackRefPF();
00655 reco::TrackRef kftrackref= (*trackref).trackRef();
00656 assert( !gsfref.isNull() );
00657 PFRecTrackRef refkf = (*gsfref).kfPFRecTrackRef();
00658 if(refkf.isNonnull()) {
00659 reco::TrackRef gsftrackref = (*refkf).trackRef();
00660 if (gsftrackref.isNonnull()&&kftrackref.isNonnull()) {
00661 if (kftrackref == gsftrackref) {
00662 dist = 0.001;
00663 } else {
00664 dist = -1.;
00665 }
00666 } else {
00667 dist = -1.;
00668 }
00669 } else {
00670 dist = -1.;
00671 }
00672
00673
00674 if(useConvBremPFRecTracks_) {
00675 if(lowEl->isLinkedToDisplacedVertex()){
00676 vector<PFRecTrackRef> pfrectrack_vec = GsfEl->GsftrackRefPF()->convBremPFRecTrackRef();
00677 if(pfrectrack_vec.size() > 0){
00678 for(unsigned int iconv = 0; iconv < pfrectrack_vec.size(); ++iconv) {
00679 if( lowEl->trackType(reco::PFBlockElement::T_FROM_GAMMACONV)) {
00680
00681 if(kftrackref == (*pfrectrack_vec[iconv]).trackRef()) {
00682 dist = 0.001;
00683 }
00684 }
00685 else{
00686
00687 reco::TrackBaseRef newTrackBaseRef((*pfrectrack_vec[iconv]).trackRef());
00688 reco::TrackBaseRef elemTrackBaseRef(kftrackref);
00689 if(newTrackBaseRef == elemTrackBaseRef){
00690 dist = 0.001;
00691 }
00692 }
00693 }
00694 }
00695 }
00696 }
00697
00698
00699 break;
00700 }
00701
00702 case PFBlockLink::GSFandBREM:
00703 {
00704 const reco::PFBlockElementGsfTrack * GsfEl = dynamic_cast<const reco::PFBlockElementGsfTrack*>(lowEl);
00705 const reco::PFBlockElementBrem * BremEl = dynamic_cast<const reco::PFBlockElementBrem*>(highEl);
00706 GsfPFRecTrackRef gsfref = GsfEl->GsftrackRefPF();
00707 GsfPFRecTrackRef bremref = BremEl->GsftrackRefPF();
00708 assert( !gsfref.isNull() );
00709 assert( !bremref.isNull() );
00710 if (gsfref == bremref) {
00711 dist = 0.001;
00712 } else {
00713 dist = -1.;
00714 }
00715 break;
00716 }
00717 case PFBlockLink::GSFandGSF:
00718 {
00719 const reco::PFBlockElementGsfTrack * lowGsfEl =
00720 dynamic_cast<const reco::PFBlockElementGsfTrack*>(lowEl);
00721 const reco::PFBlockElementGsfTrack * highGsfEl =
00722 dynamic_cast<const reco::PFBlockElementGsfTrack*>(highEl);
00723
00724 GsfPFRecTrackRef lowgsfref = lowGsfEl->GsftrackRefPF();
00725 GsfPFRecTrackRef highgsfref = highGsfEl->GsftrackRefPF();
00726 assert( !lowgsfref.isNull() );
00727 assert( !highgsfref.isNull() );
00728
00729 if( (lowGsfEl->trackType(reco::PFBlockElement::T_FROM_GAMMACONV) == false &&
00730 highGsfEl->trackType(reco::PFBlockElement::T_FROM_GAMMACONV)) ||
00731 (highGsfEl->trackType(reco::PFBlockElement::T_FROM_GAMMACONV) == false &&
00732 lowGsfEl->trackType(reco::PFBlockElement::T_FROM_GAMMACONV))) {
00733 if(lowgsfref->trackId() == highgsfref->trackId()) {
00734 dist = 0.001;
00735 }
00736 else {
00737 dist = -1.;
00738 }
00739 }
00740 break;
00741 }
00742 case PFBlockLink::ECALandBREM:
00743 {
00744 PFClusterRef clusterref = lowEl->clusterRef();
00745 assert( !clusterref.isNull() );
00746 const reco::PFBlockElementBrem * BremEl =
00747 dynamic_cast<const reco::PFBlockElementBrem*>(highEl);
00748 const PFRecTrack * myTrack = &(BremEl->trackPF());
00749
00750
00751
00752
00753
00754 bool isBrem = true;
00755 if ( myTrack->extrapolatedPoint( reco::PFTrajectoryPoint::ECALShowerMax ).isValid() )
00756 dist = LinkByRecHit::testTrackAndClusterByRecHit( *myTrack, *clusterref, isBrem, debug_);
00757 else
00758 dist = -1.;
00759 if( debug_ && dist > 0. )
00760 std::cout << "ECALandBREM: dist testTrackAndClusterByRecHit "
00761 << dist << std::endl;
00762
00763 break;
00764 }
00765 case PFBlockLink::HCALandGSF:
00766 {
00767 PFClusterRef clusterref = lowEl->clusterRef();
00768 assert( !clusterref.isNull() );
00769 const reco::PFBlockElementGsfTrack * GsfEl = dynamic_cast<const reco::PFBlockElementGsfTrack*>(highEl);
00770 const PFRecTrack * myTrack = &(GsfEl->GsftrackPF());
00771 if ( myTrack->extrapolatedPoint( reco::PFTrajectoryPoint::HCALEntrance ).isValid() )
00772 dist = LinkByRecHit::testTrackAndClusterByRecHit( *myTrack, *clusterref, false, debug_ );
00773 else
00774 dist = -1.;
00775
00776
00777 break;
00778 }
00779 case PFBlockLink::HCALandBREM:
00780 {
00781 PFClusterRef clusterref = lowEl->clusterRef();
00782 assert( !clusterref.isNull() );
00783 const reco::PFBlockElementBrem * BremEl = dynamic_cast<const reco::PFBlockElementBrem*>(highEl);
00784 const PFRecTrack * myTrack = &(BremEl->trackPF());
00785 bool isBrem = true;
00786 if ( myTrack->extrapolatedPoint( reco::PFTrajectoryPoint::HCALEntrance ).isValid() )
00787 dist = LinkByRecHit::testTrackAndClusterByRecHit( *myTrack, *clusterref, isBrem, debug_);
00788 else
00789 dist = -1.;
00790 break;
00791 }
00792 case PFBlockLink::SCandECAL:
00793 {
00794 PFClusterRef clusterref = lowEl->clusterRef();
00795
00796 assert( !clusterref.isNull() );
00797
00798 const reco::PFBlockElementSuperCluster * scEl =
00799 dynamic_cast<const reco::PFBlockElementSuperCluster*>(highEl);
00800 assert (!scEl->superClusterRef().isNull());
00801 dist = testSuperClusterPFCluster(scEl->superClusterRef(),
00802 clusterref);
00803 break;
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 default:
00860 dist = -1.;
00861
00862
00863
00864 return;
00865 }
00866 }
00867
00868 double
00869 PFBlockAlgo::testTrackAndPS(const PFRecTrack& track,
00870 const PFCluster& ps) const {
00871
00872 #ifdef PFLOW_DEBUG
00873
00874
00875 double dx=0.;
00876 double dy=0.;
00877
00878 unsigned layerid =0;
00879
00880 switch (ps.layer()) {
00881 case PFLayer::PS1:
00882 layerid = reco::PFTrajectoryPoint::PS1;
00883
00884
00885 dx = resPSpitch_;
00886 dy = resPSlength_;
00887 break;
00888 case PFLayer::PS2:
00889 layerid = reco::PFTrajectoryPoint::PS2;
00890
00891 dy = resPSpitch_;
00892 dx = resPSlength_;
00893 break;
00894 default:
00895 break;
00896 }
00897 const reco::PFTrajectoryPoint& atPS
00898 = track.extrapolatedPoint( layerid );
00899
00900 if( ! atPS.isValid() ) return -1.;
00901
00902 double trackx = atPS.position().X();
00903 double tracky = atPS.position().Y();
00904 double trackz = atPS.position().Z();
00905
00906
00907 double psx = ps.position().X();
00908 double psy = ps.position().Y();
00909
00910 double psz = ps.position().Z();
00911 if( trackz*psz < 0.) return -1.;
00912
00913
00914
00915
00916 double dist = std::sqrt( (psx-trackx)*(psx-trackx)
00917 + (psy-tracky)*(psy-tracky));
00918 if(debug_) cout<<"testTrackAndPS "<< dist <<" "<<endl;
00919 if(debug_){
00920 cout<<" trackx " << trackx
00921 <<" tracky " << tracky
00922 <<" psx " << psx
00923 <<" psy " << psy
00924 << endl;
00925 }
00926 #endif
00927
00928
00929 return -1.;
00930 }
00931
00932 double
00933 PFBlockAlgo::testECALAndHCAL(const PFCluster& ecal,
00934 const PFCluster& hcal) const {
00935
00936
00937
00938 double dist = fabs(ecal.positionREP().Eta()) > 2.5 ?
00939 LinkByRecHit::computeDist( ecal.positionREP().Eta(),
00940 ecal.positionREP().Phi(),
00941 hcal.positionREP().Eta(),
00942 hcal.positionREP().Phi() )
00943 :
00944 -1.;
00945
00946 #ifdef PFLOW_DEBUG
00947 if(debug_) cout<<"testECALAndHCAL "<< dist <<" "<<endl;
00948 if(debug_){
00949 cout<<" ecaleta " << ecal.positionREP().Eta()
00950 <<" ecalphi " << ecal.positionREP().Phi()
00951 <<" hcaleta " << hcal.positionREP().Eta()
00952 <<" hcalphi " << hcal.positionREP().Phi()
00953 }
00954 #endif
00955
00956 if ( dist < 0.2 ) return dist;
00957
00958
00959 return -1.;
00960 }
00961
00962 double
00963 PFBlockAlgo::testHCALAndHO(const PFCluster& hcal,
00964 const PFCluster& ho) const {
00965
00966 double dist = fabs(hcal.positionREP().Eta()) < 1.5 ?
00967 LinkByRecHit::computeDist( hcal.positionREP().Eta(),
00968 hcal.positionREP().Phi(),
00969 ho.positionREP().Eta(),
00970 ho.positionREP().Phi() )
00971 :
00972 -1.;
00973
00974 #ifdef PFLOW_DEBUG
00975 if(debug_) cout<<"testHCALAndHO "<< dist <<" "<<endl;
00976 if(debug_){
00977 cout<<" hcaleta " << hcal.positionREP().Eta()
00978 <<" hcalphi " << hcal.positionREP().Phi()
00979 <<" hoeta " << ho.positionREP().Eta()
00980 <<" hophi " << ho.positionREP().Phi()
00981 <<" dist " << dist<<endl;
00982 }
00983 #endif
00984
00985 if ( dist < 0.20 ) return dist;
00986
00987
00988 return -1.;
00989 }
00990
00991
00992
00993 double
00994 PFBlockAlgo::testLinkBySuperCluster(const PFClusterRef& ecal1,
00995 const PFClusterRef& ecal2) const {
00996
00997
00998
00999 double dist = -1;
01000
01001
01002 int testindex=pfcSCVec_[ecal1.key()];
01003 if(testindex == -1.) return dist;
01004
01005
01006
01007 const std::vector<reco::PFClusterRef> & thePFClusters(scpfcRefs_[testindex]);
01008
01009 unsigned npf=thePFClusters.size();
01010 for(unsigned i=0;i<npf;++i)
01011 {
01012 if(thePFClusters[i]==ecal2)
01013 {
01014 dist=LinkByRecHit::computeDist( ecal1->positionREP().Eta(),
01015 ecal1->positionREP().Phi(),
01016 ecal2->positionREP().Eta(),
01017 ecal2->positionREP().Phi() );
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027 return dist;
01028 }
01029 }
01030 return dist;
01031 }
01032
01033
01034 double
01035 PFBlockAlgo::testSuperClusterPFCluster(const SuperClusterRef& ecal1,
01036 const PFClusterRef& ecal2) const {
01037
01038
01039
01040 double dist = -1;
01041
01042 bool overlap=ClusterClusterMapping::overlap(*ecal1,*ecal2);
01043
01044 if(overlap) {
01045 dist=LinkByRecHit::computeDist( ecal1->position().eta(),
01046 ecal1->position().phi(),
01047 ecal2->positionREP().Eta(),
01048 ecal2->positionREP().Phi() );
01049 return dist;
01050 }
01051 return dist;
01052 }
01053
01054
01055
01056 double
01057 PFBlockAlgo::testPS1AndPS2(const PFCluster& ps1,
01058 const PFCluster& ps2) const {
01059
01060 #ifdef PFLOW_DEBUG
01061
01062
01063
01064
01065
01066
01067 double x1 = ps1.position().X();
01068 double y1 = ps1.position().Y();
01069 double z1 = ps1.position().Z();
01070 double x2 = ps2.position().X();
01071 double y2 = ps2.position().Y();
01072 double z2 = ps2.position().Z();
01073
01074 if (z1*z2<0.) -1.;
01075
01076 double scale = z2/z1;
01077 double x1atPS2 = x1*scale;
01078 double y1atPS2 = y1*scale;
01079
01080
01081 double dx1dx1 = resPSpitch_*resPSpitch_*scale*scale;
01082 double dy1dy1 = resPSlength_*resPSlength_*scale*scale;
01083
01084 double dy2dy2 = resPSpitch_*resPSpitch_;
01085 double dx2dx2 = resPSlength_*resPSlength_;
01086
01087
01088
01089
01090 double dist = std::sqrt( (x2-x1atPS2)*(x2-x1atPS2)
01091 + (y2-y1atPS2)*(y2-y1atPS2));
01092
01093 if(debug_) cout<<"testPS1AndPS2 "<<dist<<" "<<endl;
01094 if(debug_){
01095 cout<<" x1atPS2 "<< x1atPS2 << " dx1 "<<resPSpitch_*scale
01096 <<" y1atPS2 "<< y1atPS2 << " dy1 "<<resPSlength_*scale<< endl
01097 <<" x2 " <<x2 << " dx2 "<<resPSlength_
01098 <<" y2 " << y2 << " dy2 "<<resPSpitch_<< endl;
01099 }
01100 #endif
01101
01102
01103 return -1.;
01104 }
01105
01106
01107
01108 double
01109 PFBlockAlgo::testLinkByVertex( const reco::PFBlockElement* elt1,
01110 const reco::PFBlockElement* elt2) const {
01111
01112
01113
01114 double result=-1.;
01115
01116 reco::PFBlockElement::TrackType T_TO_DISP = reco::PFBlockElement::T_TO_DISP;
01117 reco::PFBlockElement::TrackType T_FROM_DISP = reco::PFBlockElement::T_FROM_DISP;
01118 PFDisplacedTrackerVertexRef ni1_TO_DISP = elt1->displacedVertexRef(T_TO_DISP);
01119 PFDisplacedTrackerVertexRef ni2_TO_DISP = elt2->displacedVertexRef(T_TO_DISP);
01120 PFDisplacedTrackerVertexRef ni1_FROM_DISP = elt1->displacedVertexRef(T_FROM_DISP);
01121 PFDisplacedTrackerVertexRef ni2_FROM_DISP = elt2->displacedVertexRef(T_FROM_DISP);
01122
01123 if( ni1_TO_DISP.isNonnull() && ni2_FROM_DISP.isNonnull())
01124 if( ni1_TO_DISP == ni2_FROM_DISP ) { result = 1.0; return result; }
01125
01126 if( ni1_FROM_DISP.isNonnull() && ni2_TO_DISP.isNonnull())
01127 if( ni1_FROM_DISP == ni2_TO_DISP ) { result = 1.0; return result; }
01128
01129 if( ni1_FROM_DISP.isNonnull() && ni2_FROM_DISP.isNonnull())
01130 if( ni1_FROM_DISP == ni2_FROM_DISP ) { result = 1.0; return result; }
01131
01132
01133 if ( elt1->trackType(reco::PFBlockElement::T_FROM_GAMMACONV) &&
01134 elt2->trackType(reco::PFBlockElement::T_FROM_GAMMACONV) ) {
01135
01136 if(debug_ ) std::cout << " testLinkByVertex On Conversions " << std::endl;
01137
01138 if ( elt1->convRef().isNonnull() && elt2->convRef().isNonnull() ) {
01139 if(debug_ ) std::cout << " PFBlockAlgo.cc testLinkByVertex Cconversion Refs are non null " << std::endl;
01140 if ( elt1->convRef() == elt2->convRef() ) {
01141 result=1.0;
01142 if(debug_ ) std::cout << " testLinkByVertex Cconversion Refs are equal " << std::endl;
01143 return result;
01144 }
01145 }
01146
01147 }
01148
01149 if ( elt1->trackType(reco::PFBlockElement::T_FROM_V0) &&
01150 elt2->trackType(reco::PFBlockElement::T_FROM_V0) ) {
01151 if(debug_ ) std::cout << " testLinkByVertex On V0 " << std::endl;
01152 if ( elt1->V0Ref().isNonnull() && elt2->V0Ref().isNonnull() ) {
01153 if(debug_ ) std::cout << " PFBlockAlgo.cc testLinkByVertex V0 Refs are non null " << std::endl;
01154 if ( elt1->V0Ref() == elt2->V0Ref() ) {
01155 result=1.0;
01156 if(debug_ ) std::cout << " testLinkByVertex V0 Refs are equal " << std::endl;
01157 return result;
01158 }
01159 }
01160 }
01161
01162 return result;
01163 }
01164
01165
01166
01167 void
01168 PFBlockAlgo::checkMaskSize( const reco::PFRecTrackCollection& tracks,
01169 const reco::GsfPFRecTrackCollection& gsftracks,
01170 const reco::PFClusterCollection& ecals,
01171 const reco::PFClusterCollection& hcals,
01172 const reco::PFClusterCollection& hos,
01173 const reco::PFClusterCollection& hfems,
01174 const reco::PFClusterCollection& hfhads,
01175 const reco::PFClusterCollection& pss,
01176 const reco::PhotonCollection& egphh,
01177 const Mask& trackMask,
01178 const Mask& gsftrackMask,
01179 const Mask& ecalMask,
01180 const Mask& hcalMask,
01181 const Mask& hoMask,
01182 const Mask& hfemMask,
01183 const Mask& hfhadMask,
01184 const Mask& psMask,
01185 const Mask& phMask) const {
01186
01187 if( !trackMask.empty() &&
01188 trackMask.size() != tracks.size() ) {
01189 string err = "PFBlockAlgo::setInput: ";
01190 err += "The size of the track mask is different ";
01191 err += "from the size of the track vector.";
01192 throw std::length_error( err.c_str() );
01193 }
01194
01195 if( !gsftrackMask.empty() &&
01196 gsftrackMask.size() != gsftracks.size() ) {
01197 string err = "PFBlockAlgo::setInput: ";
01198 err += "The size of the gsf track mask is different ";
01199 err += "from the size of the gsftrack vector.";
01200 throw std::length_error( err.c_str() );
01201 }
01202
01203 if( !ecalMask.empty() &&
01204 ecalMask.size() != ecals.size() ) {
01205 string err = "PFBlockAlgo::setInput: ";
01206 err += "The size of the ecal mask is different ";
01207 err += "from the size of the ecal clusters vector.";
01208 throw std::length_error( err.c_str() );
01209 }
01210
01211 if( !hcalMask.empty() &&
01212 hcalMask.size() != hcals.size() ) {
01213 string err = "PFBlockAlgo::setInput: ";
01214 err += "The size of the hcal mask is different ";
01215 err += "from the size of the hcal clusters vector.";
01216 throw std::length_error( err.c_str() );
01217 }
01218
01219 if( !hoMask.empty() &&
01220 hoMask.size() != hos.size() ) {
01221 string err = "PFBlockAlgo::setInput: ";
01222 err += "The size of the ho mask is different ";
01223 err += "from the size of the ho clusters vector.";
01224 throw std::length_error( err.c_str() );
01225 }
01226
01227
01228 if( !hfemMask.empty() &&
01229 hfemMask.size() != hfems.size() ) {
01230 string err = "PFBlockAlgo::setInput: ";
01231 err += "The size of the hfem mask is different ";
01232 err += "from the size of the hfem clusters vector.";
01233 throw std::length_error( err.c_str() );
01234 }
01235
01236 if( !hfhadMask.empty() &&
01237 hfhadMask.size() != hfhads.size() ) {
01238 string err = "PFBlockAlgo::setInput: ";
01239 err += "The size of the hfhad mask is different ";
01240 err += "from the size of the hfhad clusters vector.";
01241 throw std::length_error( err.c_str() );
01242 }
01243
01244 if( !psMask.empty() &&
01245 psMask.size() != pss.size() ) {
01246 string err = "PFBlockAlgo::setInput: ";
01247 err += "The size of the ps mask is different ";
01248 err += "from the size of the ps clusters vector.";
01249 throw std::length_error( err.c_str() );
01250 }
01251
01252 if( !phMask.empty() &&
01253 phMask.size() != egphh.size() ) {
01254 string err = "PFBlockAlgo::setInput: ";
01255 err += "The size of the photon mask is different ";
01256 err += "from the size of the photon vector.";
01257 throw std::length_error( err.c_str() );
01258 }
01259
01260 }
01261
01262
01263 std::ostream& operator<<(std::ostream& out, const PFBlockAlgo& a) {
01264 if(! out) return out;
01265
01266 out<<"====== Particle Flow Block Algorithm ======= ";
01267 out<<endl;
01268 out<<"number of unassociated elements : "<<a.elements_.size()<<endl;
01269 out<<endl;
01270
01271 for(PFBlockAlgo::IEC ie = a.elements_.begin();
01272 ie != a.elements_.end(); ++ie) {
01273 out<<"\t"<<**ie <<endl;
01274 }
01275
01276
01277
01278
01279 const std::auto_ptr< reco::PFBlockCollection >& blocks
01280 = a.blocks();
01281
01282 if(!blocks.get() ) {
01283 out<<"blocks already transfered"<<endl;
01284 }
01285 else {
01286 out<<"number of blocks : "<<blocks->size()<<endl;
01287 out<<endl;
01288
01289 for(PFBlockAlgo::IBC ib=blocks->begin();
01290 ib != blocks->end(); ++ib) {
01291 out<<(*ib)<<endl;
01292 }
01293 }
01294
01295 return out;
01296 }
01297
01298 bool
01299 PFBlockAlgo::goodPtResolution( const reco::TrackRef& trackref) {
01300
01301 double P = trackref->p();
01302 double Pt = trackref->pt();
01303 double DPt = trackref->ptError();
01304 unsigned int NHit = trackref->hitPattern().trackerLayersWithMeasurement();
01305 unsigned int NLostHit = trackref->hitPattern().trackerLayersWithoutMeasurement();
01306 unsigned int LostHits = trackref->numberOfLostHits();
01307 double sigmaHad = sqrt(1.20*1.20/P+0.06*0.06) / (1.+LostHits);
01308
01309
01310 unsigned int Algo = 0;
01311 switch (trackref->algo()) {
01312 case TrackBase::ctf:
01313 case TrackBase::iter0:
01314 case TrackBase::iter1:
01315 case TrackBase::iter2:
01316 Algo = 0;
01317 break;
01318 case TrackBase::iter3:
01319 Algo = 1;
01320 break;
01321 case TrackBase::iter4:
01322 Algo = 2;
01323 break;
01324 case TrackBase::iter5:
01325 Algo = 3;
01326 break;
01327 case TrackBase::iter6:
01328 Algo = 4;
01329 break;
01330 default:
01331 Algo = useIterTracking_ ? 5 : 0;
01332 break;
01333 }
01334
01335
01336 if ( P < 0.05 ) return false;
01337
01338
01339 if ( Algo > 4 ) return false;
01340
01341 if (debug_) cout << " PFBlockAlgo: PFrecTrack->Track Pt= "
01342 << Pt << " DPt = " << DPt << endl;
01343 if ( ( DPtovPtCut_[Algo] > 0. &&
01344 DPt/Pt > DPtovPtCut_[Algo]*sigmaHad ) ||
01345 NHit < NHitCut_[Algo] ) {
01346
01347 if (debug_) cout << " PFBlockAlgo: skip badly measured track"
01348 << ", P = " << P
01349 << ", Pt = " << Pt
01350 << " DPt = " << DPt
01351 << ", N(hits) = " << NHit << " (Lost : " << LostHits << "/" << NLostHit << ")"
01352 << ", Algo = " << Algo
01353 << endl;
01354 if (debug_) cout << " cut is DPt/Pt < " << DPtovPtCut_[Algo] * sigmaHad << endl;
01355 if (debug_) cout << " cut is NHit >= " << NHitCut_[Algo] << endl;
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365 return false;
01366 }
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 return true;
01378 }
01379
01380 int
01381 PFBlockAlgo::muAssocToTrack( const reco::TrackRef& trackref,
01382 const edm::Handle<reco::MuonCollection>& muonh) const {
01383 if(muonh.isValid() ) {
01384 for(unsigned j=0;j<muonh->size(); ++j) {
01385 reco::MuonRef muonref( muonh, j );
01386 if (muonref->track().isNonnull())
01387 if( muonref->track() == trackref ) return j;
01388 }
01389 }
01390 return -1;
01391 }
01392
01393 int
01394 PFBlockAlgo::muAssocToTrack( const reco::TrackRef& trackref,
01395 const edm::OrphanHandle<reco::MuonCollection>& muonh) const {
01396 if(muonh.isValid() ) {
01397 for(unsigned j=0;j<muonh->size(); ++j) {
01398 reco::MuonRef muonref( muonh, j );
01399 if (muonref->track().isNonnull())
01400 if( muonref->track() == trackref ) return j;
01401 }
01402 }
01403 return -1;
01404 }
01405
01406
01407
01408
01409 inline bool
01410 PFBlockAlgo::linkPrefilter(const reco::PFBlockElement* last, const reco::PFBlockElement* next) const {
01411
01412 PFBlockElement::Type type1 = (last)->type();
01413 PFBlockElement::Type type2 = (next)->type();
01414
01415 if( type1==type2 ) {
01416
01417
01418 if( type1!=PFBlockElement::TRACK && type1!=PFBlockElement::GSF &&
01419 type1!=PFBlockElement::ECAL) {
01420 return false;
01421 }
01422
01423 if (type1==PFBlockElement::ECAL && bNoSuperclus_) return false;
01424
01425
01426 if( type1 ==PFBlockElement::TRACK) {
01427 if ( !((last)->isLinkedToDisplacedVertex()) || !((next)->isLinkedToDisplacedVertex()))
01428 return false;
01429 }
01430 }
01431
01432 if ((type1 == PFBlockElement::PS1 || type1 == PFBlockElement::PS2) && (type2 != PFBlockElement::ECAL)) return false;
01433 if ((type2 == PFBlockElement::PS1 || type2 == PFBlockElement::PS2) && (type1 != PFBlockElement::ECAL)) return false;
01434 if ((type1 == PFBlockElement::HFEM && type2 != PFBlockElement::HFHAD) || (type1 == PFBlockElement::HFHAD && type2 != PFBlockElement::HFEM)) return false;
01435
01436 if (useKDTreeTrackEcalLinker_){
01437
01438 if ( type1 == PFBlockElement::TRACK && type2 == PFBlockElement::ECAL)
01439 if ( last->isMultilinksValide() && last->getMultilinks().size()==0 ) return false;
01440 if ( type2 == PFBlockElement::TRACK && type1 == PFBlockElement::ECAL)
01441 if ( next->isMultilinksValide() && next->getMultilinks().size()==0 ) return false;
01442 if ( type1 == PFBlockElement::PS1 || type1 == PFBlockElement::PS2)
01443 if ( last->isMultilinksValide() && last->getMultilinks().size()==0 ) return false;
01444 if ( type2 == PFBlockElement::PS1 || type2 == PFBlockElement::PS2)
01445 if ( next->isMultilinksValide() && next->getMultilinks().size()==0 ) return false;
01446
01447 }
01448
01449 return true;
01450
01451 }
01452