CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch12/src/L1Trigger/RPCTrigger/src/RPCStripsRing.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     RPCConeBuilder
00004 // Class  :     RPCStripsRing
00005 // 
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Tomasz Fruboes
00010 //         Created:  Tue Feb 26 15:13:10 CET 2008
00011 // $Id: RPCStripsRing.cc,v 1.2 2009/09/15 13:49:41 fruboes Exp $
00012 //
00013 
00014 // system include files
00015 
00016 // user include files
00017 //#include "L1TriggerConfig/RPCConeBuilder/interface/RPCStripsRing.h"
00018 #include "L1Trigger/RPCTrigger/interface/RPCStripsRing.h"
00019 #include "Geometry/RPCGeometry/interface/RPCGeomServ.h"
00020 #include "DataFormats/MuonDetId/interface/RPCDetId.h"
00021 #include "Geometry/RPCGeometry/interface/RPCGeometry.h"
00022 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00023 
00024 RPCStripsRing::RPCStripsRing() :
00025     m_hwPlane(-1),
00026     m_etaPartition(99),
00027     m_region(-2),
00028     m_isReferenceRing(false),
00029     m_didVirtuals(false),
00030     m_didFiltering(false)
00031 {
00032 
00033 }
00034 
00035 RPCStripsRing::RPCStripsRing(const RPCRoll * roll,
00036                              boost::shared_ptr<L1RPCConeBuilder::TConMap > cmap) :
00037     m_didVirtuals(false),
00038     m_didFiltering(false),
00039     m_connectionsMap(cmap)
00040 {
00041   
00042   RPCDetId detId = roll->id();
00043   RPCGeomServ grs(detId);
00044   
00045   m_etaPartition = grs.eta_partition();
00046   m_hwPlane = calculateHwPlane(roll);
00047   
00048   m_isReferenceRing = false;
00049   
00050   m_region = detId.region();
00051   
00052   int ring = detId.ring();
00053   
00054   if (m_region == 0 && std::abs(ring)<2 && m_hwPlane == 2) // for barell wheel -1,0,1 refplane is hwPlane=2
00055       m_isReferenceRing = true;
00056   else if (m_region == 0 && std::abs(ring)==2 && m_hwPlane == 6) // for barell wheel -2,2 refplane is hwPlane=6
00057       m_isReferenceRing = true;
00058   else if (m_region != 0 && m_hwPlane == 2) // for endcaps
00059       m_isReferenceRing = true;
00060   
00061   
00062   if( getRingId() == 2008 || getRingId() == 2108) //exception: endcaps;hwplane 2;farest roll from beam
00063       m_isReferenceRing = false;
00064     
00065   addRoll(roll);
00066 }
00067 
00068 
00069 void RPCStripsRing::addRoll(const RPCRoll * roll){
00070 
00071 //  RPCDetId detId = roll->id();
00072   
00073   if (getRingId() !=  getRingId(roll) ){
00074      throw cms::Exception("RPCInternal") << "RPCStripsRing::addRoll ringsIds dont match \n";
00075   }
00076   
00077   //iterate over the strips of this roll
00078   for (int i=1; i<=roll->nstrips(); i++ ) { 
00079     
00080        LocalPoint lStripCentre = roll->centreOfStrip(i);
00081        GlobalPoint gStripCentre = roll->toGlobal(lStripCentre);
00082        float phiRaw = gStripCentre.phi();
00083        
00084        TStrip newStrip(roll->id().rawId(), i);
00085        (*this)[phiRaw] = newStrip;
00086        
00087   }
00088 
00089 }
00090 
00091 int RPCStripsRing::getRingId(int etaPart, int hwPlane){
00092 
00093   int sign = 1; // positive
00094   if (etaPart < 0){
00095     sign = 0;
00096   }
00097    
00098   return  1000*(hwPlane) +     //1...6
00099           100*( sign ) + //
00100           1*( std::abs(etaPart) );     //-17...17
00101   
00102 }
00103 
00104 int RPCStripsRing::getRingId(){
00105 
00106   return getRingId(m_etaPartition, m_hwPlane);
00107    
00108 }
00109 
00110 int RPCStripsRing::getRingId(const RPCRoll * roll) {
00111 
00112       
00113    RPCDetId detId = roll->id();
00114    RPCGeomServ grs(detId);
00115    int etaPartition = grs.eta_partition();
00116    int hwPlane = calculateHwPlane(roll);
00117    
00118    return getRingId(etaPartition, hwPlane);
00119       
00120 }
00121 
00122 
00123 //  hwPlane is  station number for endcaps
00124 //  for barrell numbering goes 1 5 2 6 3 4 (first number means plane closest to the beam)
00125 int RPCStripsRing::calculateHwPlane(const RPCRoll * roll){
00126 
00127   int hwPlane = -1;  
00128   RPCDetId detId = roll->id();
00129   int station = detId.station();
00130   int layer = detId.layer(); 
00131   int region = detId.region(); 
00132   
00133   if (region != 0){ // endcaps
00134     hwPlane = station;
00135   }
00136   // Now comes the barell
00137   else if ( station > 2 ){
00138     hwPlane = station;
00139   } 
00140   else if ( station == 1 && layer == 1) {
00141     hwPlane = 1;
00142   }
00143   else if ( station == 1 && layer == 2) {
00144     hwPlane = 5;
00145   }
00146   else if ( station == 2 && layer == 1) {
00147     hwPlane = 2;
00148   }
00149   else if ( station == 2 && layer == 2) {
00150     hwPlane = 6;
00151   } 
00152   
00153   /*if (hwPlane < 1)
00154     std::cout << "prb: " << hwPlane << " "
00155         << region << " "
00156         << station << " "
00157   << layer << std::endl;*/
00158   if (hwPlane < 0) {
00159       throw cms::Exception("RPCInternal") << "Calculated negative hwplane \n";
00160   }
00161   
00162   
00163   return hwPlane;
00164   
00165 }
00166 
00167 void RPCStripsRing::filterOverlapingChambers(){
00168     
00169   if(m_didFiltering) return;
00170   m_didFiltering = true;
00171   
00172   if (m_region != 0 || m_hwPlane != 4) 
00173      return;
00174   
00175   typedef std::map<uint32_t,int> TDetId2StripNo;
00176   TDetId2StripNo det2stripNo;
00177   
00178   // Note: we begin in middle of first chamber (ch1), we have to handle that
00179   int ch1BegStrips = 0; // no of strips on the begining of the map (first=last chamber of map)
00180   int ch1EndStrips = 0; // no of strips on the end of the map (first=last chamber of map)
00181   
00182   // How many strips has each chamber?
00183   RPCStripsRing::iterator it = this->begin();
00184   uint32_t ch1Det = it->second.m_detRawId;
00185   for (; it!=this->end(); ++it){
00186     
00187     if ( det2stripNo.find(it->second.m_detRawId) == det2stripNo.end()){
00188       det2stripNo[it->second.m_detRawId]=1;      // Add new chamber to a map, set strip cnt to 1
00189     } else {
00190       ++det2stripNo[it->second.m_detRawId];     // Increase strip count of a chamber
00191     }
00192     
00193     if (det2stripNo.size() == 1 && ch1Det == it->second.m_detRawId) {
00194       ++ch1BegStrips;
00195     } else if (ch1Det == it->second.m_detRawId){
00196       ++ch1EndStrips;
00197     }
00198     
00199   }
00200   
00201   det2stripNo[ch1Det]-=ch1EndStrips;
00202   
00203  // std::cout << ch1BegStrips << " " << ch1EndStrips << std::endl;
00204   
00205   //TDetId2StripNo::iterator itIds = det2stripNo.begin();
00206   //for(;itIds!=det2stripNo.end();++itIds){
00207 //    std::cout << itIds->first << " " << itIds->second << std::endl;
00208 //  }
00209   
00210   
00211   
00212   it = this->begin();
00213   uint32_t lastDet = it->second.m_detRawId;
00214   while ( it!=this->end() ){
00215     
00216     if (det2stripNo[it->second.m_detRawId] < 0) {
00217       throw cms::Exception("RPCInternal") << " RPCStripsRing::filterOverlapingChambers() - no strips left \n";
00218     }
00219     if ( it->second.m_detRawId == lastDet) {
00220       --det2stripNo[lastDet];
00221       ++it;
00222     } else if (det2stripNo[lastDet] == 0) { // no more strips left in lastDet, proceed to new det
00223       
00224       if (lastDet == ch1Det) {
00225         det2stripNo[ch1Det]+=ch1EndStrips;
00226       }
00227       
00228       lastDet = it->second.m_detRawId;
00229       --det2stripNo[lastDet];
00230       ++it;
00231     } else { // there are still strips in last det, delete current strip
00232       --det2stripNo[it->second.m_detRawId];
00233       RPCStripsRing::iterator itErase = it;
00234       ++it;
00235       //std::cout << "Removing strip " <<  it->second.m_detRawId << " " << (int)it->second.m_strip << std::endl;
00236       this->erase(itErase); 
00237     }
00238     
00239   }
00240   
00241   
00242 
00243 }
00244 
00245 void RPCStripsRing::fillWithVirtualStrips()
00246 {
00247   
00248 
00249   if(m_didVirtuals) return;
00250   m_didVirtuals = true;
00251 
00252   const float pi = 3.141592654;
00253   double dphi=2.0*pi/1152; // defines angular granulation of strips.
00254   
00255   RPCStripsRing stripsToInsert;
00256     
00257   
00258   float delta = 0;
00259   int stripsToAdd = 0;
00260   
00261   
00262   RPCStripsRing::iterator it = this->begin();
00263   RPCStripsRing::iterator itLast = this->begin();
00264   for (; it!=this->end(); ++it){
00265   
00266     /*std::cout << it->first << " "
00267         << it->second.m_detRawId << " "
00268         << (int)it->second.m_strip << std::endl;
00269     */
00270     
00271     delta = it->first - itLast->first;        
00272     if (it == itLast || // skip first loop iteration
00273         itLast->second.m_detRawId == it->second.m_detRawId || // insert strips between two chambers only
00274         delta < 0)
00275     {
00276       itLast = it;
00277       continue;
00278     }
00279     
00280     
00281     stripsToAdd = (int)std::floor(delta/dphi)-1;
00282     //std::cout << delta << " " << stripsToAdd << std::endl;
00283     
00284     if ( isReferenceRing() && m_hwPlane==6) ++stripsToAdd;
00285     
00286     for (int i = 0;i<stripsToAdd;++i){
00287       
00288       stripsToInsert[itLast->first+dphi*(i+1)]=TStrip();
00289     
00290     }
00291     
00292     itLast = it; 
00293   }
00294   // TODO: check delta between first and last strip in map
00295   
00296   this->insert(stripsToInsert.begin(),stripsToInsert.end());
00297 
00298   
00299   
00300 }
00301 void RPCStripsRing::createRefConnections(TOtherConnStructVec & otherRings, int logplane, int logplaneSize)
00302 {
00303   //*
00304    /*std::cout << "RefCon for " << getRingId() 
00305        << " (" << getEtaPartition()<<  ")"
00306        << " tower: " << getTowerForRefRing()
00307        << " ; connected: "
00308        << otherRings.size() 
00309        << std::endl
00310        << std::endl;    
00311   //*/
00312        
00313   // XXX - TODO: warning on wrong logplaneSize
00314   
00315    if(!this->isReferenceRing()){
00316       throw cms::Exception("RPCInternal") << " RPCStripsRing::createRefConnections "
00317          << " called for non-reference ring \n";
00318    }
00319    
00320    if (logplaneSize!=8) {
00321      throw cms::Exception("RPCInternal") << " RPCStripsRing::createRefConnections "
00322          << " called for lpSize " << logplaneSize << " \n";
00323      
00324    }
00325    const float pi = 3.141592654;
00326    const float offset = (5./360.)*2*pi; // XXX
00327    
00328    //find first reference strip of first PAC (the strip with phi ~= 5deg)
00329    RPCStripsRing::iterator starEndIt = this->begin();
00330    while ( (++starEndIt)->first < offset ); 
00331          
00332    RPCStripsRing::iterator it = starEndIt;
00333    //--starEndIt;
00334    
00335    float angle = 0;
00336    int curPACno = -1;
00337    int curStripNo = 0;
00338    int curBegStripNo=0;
00339    
00340   bool firstIter = true;
00341 
00342    while(it!=starEndIt || firstIter ) { // iterate over strips
00343  
00344 
00345      firstIter = false;
00346       // New PAC  
00347      if(curStripNo%logplaneSize==0){ 
00348          ++curPACno; 
00349          curBegStripNo=curStripNo;
00350          RPCStripsRing::iterator plus8 = it;
00351          bool skipOccured = false;
00352          for (int i=0;i<7;++i){  
00353             ++plus8;
00354             if (plus8==this->end()){
00355                plus8=this->begin();
00356                skipOccured = true;
00357             }
00358          }
00359          
00360          // calculate angle
00361          float phi= it->first;
00362          float phiP8= plus8->first;
00363          if (skipOccured){
00364             // phiP8 is negative
00365             // phi is positive
00366             // xcheck
00367            if (phi*phiP8 > 0){
00368              throw cms::Exception("RPCInternal") << " RPCStripsRing::createRefConnections phi/phi8 error \n";
00369            }
00370            angle = (2*pi+phiP8+phi)/2;
00371            if(angle > pi){ // should land on positive side
00372               angle -= 2*pi;
00373            } 
00374             
00375            if (std::abs(angle) > pi) {
00376                throw cms::Exception("RPCInternal") << " RPCStripsRing::createRefConnections "
00377                      << " problem with angle calc \n";
00378            }
00379          }
00380          else {
00381            angle = (phiP8+phi)/2;
00382          }
00383          //std::cout << curPACno << " " << phiP8 << " " << phi << " "  << angle << std::endl;
00384          
00385          
00386          TOtherConnStructVec::iterator itOt = otherRings.begin();
00387          for (;itOt!=otherRings.end();++itOt){
00388            itOt->m_it->second.createOtherConnections(getTowerForRefRing(),
00389                                                      curPACno, 
00390                                                      itOt->m_logplane,
00391                                                      itOt->m_logplaneSize,
00392                                                      angle);
00393          }
00394       }
00395       
00396       
00397       if ( !it->second.isVirtual() ){
00398         L1RPCConeBuilder::TStripCon newCon;
00399         newCon.m_tower = getTowerForRefRing();
00400         newCon.m_PAC = curPACno;
00401         newCon.m_logplane = logplane;
00402         newCon.m_logstrip=curStripNo-curBegStripNo;
00403         //std::cout << " Adding con for " << it->second.m_detRawId << std::endl;
00404         (*m_connectionsMap)[it->second.m_detRawId][it->second.m_strip].push_back(newCon);
00405         //std::cout << " Adding ref connection " << std::endl;
00406       }
00407       ++curStripNo;
00408       ++it;
00409       if (it==this->end()){
00410          it=this->begin();
00411       }
00412        
00413    } // iteration over strips ends
00414    
00415    //std::cout << " refcon: " << curPACno << " PACs" << std::endl;
00416    //std::cout << "After refCon: " << m_connectionsMap.size() << std::endl;
00417 
00418 }
00419 
00420 void RPCStripsRing::createOtherConnections(int tower, int PACno, int logplane, int logplaneSize, float angle) {
00421 
00422    //std::cout << "    OtherCon for " << getRingId() << std::endl;
00423 
00424    if(this->isReferenceRing()){
00425       throw cms::Exception("RPCInternal") << " RPCStripsRing::createOtherConnections "
00426             << " called for reference ring \n";
00427    }
00428 
00429 
00430    RPCStripsRing::const_iterator it = this->lower_bound(angle);
00431    
00432    
00433    if (it == this->end())
00434      it = this->begin();
00435    
00436    for (int i=0; i < logplaneSize/2; i++){ 
00437      
00438       if (it==this->begin())
00439         it=this->end();  // (m_stripPhiMap.end()--) is ok.
00440       
00441       --it;
00442    }
00443   
00444      
00445    for (int i=0; i < logplaneSize; i++){
00446     
00447      if (! it->second.isVirtual() ){
00448         L1RPCConeBuilder::TStripCon newCon;
00449         newCon.m_tower = tower;
00450         newCon.m_PAC = PACno;
00451         newCon.m_logplane = logplane;
00452         newCon.m_logstrip= i;
00453         (*m_connectionsMap)[it->second.m_detRawId][it->second.m_strip].push_back(newCon);
00454         //std::cout << " Adding other connection " << std::endl;
00455       }
00456   
00457       ++it;
00458       if (it==this->end())
00459         it=this->begin();
00460    }
00461      
00462 }
00463 
00464 // Defines to which tower this ring (only ref ring) belongs
00465 int RPCStripsRing::getTowerForRefRing(){
00466 
00467   int ret = 0;
00468   
00469   if(!this->isReferenceRing()){
00470     throw cms::Exception("RPCInternal") << " RPCStripsRing::getTowerForRefRing() "
00471         << " called for non reference ring \n";
00472   }
00473 
00474   int etaAbs = std::abs(getEtaPartition());
00475   if (etaAbs < 8) {
00476     ret = getEtaPartition();
00477   } else if (etaAbs > 8) {
00478     int sign = (getEtaPartition() > 0 ? 1 : -1);
00479     ret = getEtaPartition()-sign;
00480   } else {
00481     throw cms::Exception("RPCInternal") << " RPCStripsRing::getTowerForRefRing() "
00482         << " called for etaPartition 8 \n";
00483   }
00484 
00485 
00486 
00487   return ret;
00488 
00489 }
00490 /*
00491       struct TStripCon{
00492         signed char m_tower;
00493         unsigned char m_PAC;
00494         unsigned char m_logplane;
00495         unsigned char m_logstrip;
00496       };
00497       typedef std::vector<TStripCon> TStripConVec;
00498       typedef std::map<unsigned char, TStripConVec> TStrip2ConVec;
00499       typedef std::map<uint32_t, TStrip2ConVec> TConMap;
00500 
00501       // compressed connections
00502       struct TCompressedCon{
00503         signed char m_tower;
00504         unsigned char m_PAC;
00505         signed char m_offset;
00506         signed char m_mul;
00507       };
00508       typedef std::vector<TCompressedCon> TCompressedConVec;
00509       typedef std::map<uint32_t, TCompressedConVec> TCompressedConMap;
00510 
00511 */
00512 
00513 
00514 void RPCStripsRing::compressConnections(){
00515 
00516   
00517   L1RPCConeBuilder::TConMap::iterator itChamber = m_connectionsMap->begin();
00518   
00519   boost::shared_ptr<L1RPCConeBuilder::TConMap > uncompressedConsLeft
00520   = boost::shared_ptr<L1RPCConeBuilder::TConMap >(new L1RPCConeBuilder::TConMap());
00521   
00522   m_compressedConnectionMap =        
00523                boost::shared_ptr<L1RPCConeBuilder::TCompressedConMap >
00524                (new L1RPCConeBuilder::TCompressedConMap());
00525   
00526   
00527   int compressedCons = 0, uncompressedConsBefore = 0, uncompressedConsAfter = 0;
00528   
00529 //   int offsetMin =0, offsetMax =0;
00530   
00531   for( ;itChamber!=m_connectionsMap->end(); ++itChamber ){
00532     
00533     uint32_t detId = itChamber->first;
00534     
00535     for (L1RPCConeBuilder::TStrip2ConVec::iterator itStrip = itChamber->second.begin();
00536          itStrip!=itChamber->second.end();
00537          ++itStrip)
00538     {
00539       
00540       // Iterate over strip Connections
00541       for(L1RPCConeBuilder::TStripConVec::iterator itConn = itStrip->second.begin();
00542           itConn!=itStrip->second.end(); 
00543           ++itConn)
00544       {
00545         // Check if this connection isn't allready present in the compressed map 
00546         ++uncompressedConsBefore;
00547         bool alreadyDone=false; 
00548         if (m_compressedConnectionMap->find(detId)!=m_compressedConnectionMap->end()){
00549           
00550           // iterate over the vec, check element by element
00551           for(L1RPCConeBuilder::TCompressedConVec::iterator itCompConn=(*m_compressedConnectionMap)[detId].begin();
00552               itCompConn!=(*m_compressedConnectionMap)[detId].end();
00553               ++itCompConn)
00554           {
00555             if (itCompConn->m_tower ==  itConn->m_tower
00556                 && itCompConn->m_PAC ==  itConn->m_PAC
00557                 && itCompConn->m_logplane ==  itConn->m_logplane) // connection allready compressed 
00558             {
00559               alreadyDone=true;
00560               
00561               int logStrip = itCompConn->m_mul*itStrip->first+itCompConn->m_offset;
00562               if (logStrip != itConn->m_logstrip){
00563                 //copy the problematic connection to the "safe" map
00564                 (*uncompressedConsLeft)[detId][itStrip->first].push_back(*itConn);
00565                 ++uncompressedConsAfter;
00566                 edm::LogWarning("RPCTriggerConfig") << " Compression failed for det " << detId 
00567                   << " strip " << (int)itStrip->first
00568                   << " . Got " << (int)logStrip
00569                   << " expected " << (int)itConn->m_logstrip
00570                   << std::endl;
00571               } else {
00572                 itCompConn->addStrip(itStrip->first);
00573               }
00574               
00575             }
00576           } // compressed connection iteration end
00577         }  
00578         //if (detId==637569977) std::cout << " Buld cons for strip " << (int)itStrip->first << std::endl;
00579         
00580         
00581         if (!alreadyDone){
00582             // find another strip contributing to the same PAC,tower,logplane
00583           L1RPCConeBuilder::TStrip2ConVec::iterator itStripOther = itStrip;  
00584           ++itStripOther;
00585           bool otherStripFound = false;
00586           signed char mul = 1;
00587           for (;itStripOther!=itChamber->second.end() && !otherStripFound;
00588                ++itStripOther)
00589           {
00590             for(L1RPCConeBuilder::TStripConVec::iterator itConnOther = itStripOther->second.begin();
00591                 itConnOther!=itStripOther->second.end(); 
00592                 ++itConnOther)
00593             {
00594               if (itConnOther->m_tower ==  itConn->m_tower
00595                   && itConnOther->m_PAC ==  itConn->m_PAC
00596                   && itConnOther->m_logplane ==  itConn->m_logplane) // connection to same PAC,logplane
00597               {
00598                 otherStripFound = true;
00599                 if ( (itStripOther->first-itStrip->first)*(itConnOther->m_logstrip-itConn->m_logstrip) < 0 ){
00600                   mul = -1;                
00601                 } 
00602                 break;
00603               }
00604             } // otherConnections iter ends
00605           } // otherStrip iter ends
00606           
00607           /*
00608           if (itConn->m_tower==3 && itConn->m_PAC==73 && itConn->m_logplane==4 && detId==637569977){
00609             std::cout << " Buld cons for strip " << (int)itStrip->first;
00610             if (otherStripFound)
00611               std::cout << " other strip " << itStrip->first;
00612             else 
00613               std::cout << " no other strip ";
00614             
00615             std::cout << std::endl;
00616             
00617         }*/
00618           
00619           L1RPCConeBuilder::TCompressedCon nCompConn;
00620           nCompConn.m_tower = itConn->m_tower;
00621           nCompConn.m_PAC   = itConn->m_PAC;
00622           nCompConn.m_logplane   = itConn->m_logplane;
00623           nCompConn.m_mul  = mul;
00624           nCompConn.m_offset  = itConn->m_logstrip - mul*(signed short)(itStrip->first);
00625           nCompConn.addStrip(itStrip->first);
00626           
00627           if (otherStripFound){
00628             
00629           }  else { 
00630             
00631             //  uncompressedConsLeft[detId][itStrip->first].push_back(*itConn);
00632             //  ++uncompressedConsAfter;
00633           }
00634           (*m_compressedConnectionMap)[detId].push_back(nCompConn);
00635           ++compressedCons;
00636 
00637 
00638         } // if(!allreadyDone)
00639       }// iterate on connections
00640     }// iterate on strips
00641   } // iterate on chambers
00642    
00643   // 159 -87
00644   //std::cout << offsetMax << " TT " << offsetMin << std::endl;
00645   
00646   edm::LogInfo("RPCTriggerConfig") 
00647       << " Compressed: " << compressedCons<< " " << sizeof(L1RPCConeBuilder::TCompressedCon)
00648       << " Uncompressed before: " << uncompressedConsBefore<< " " << sizeof(L1RPCConeBuilder::TStripCon)
00649       << " Uncompressed after: " << uncompressedConsAfter << " " << sizeof(L1RPCConeBuilder::TStripCon);
00650   m_connectionsMap = uncompressedConsLeft;
00651 
00652 }
00653