Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:16:10

0001 #include "Fun4AllDstInputManager.h"
0002 
0003 #include "Fun4AllReturnCodes.h"
0004 #include "Fun4AllServer.h"
0005 
0006 #include <ffaobjects/RunHeader.h>
0007 #include <ffaobjects/SyncDefs.h>
0008 #include <ffaobjects/SyncObject.h>
0009 
0010 #include <frog/FROG.h>
0011 
0012 #include <phool/PHCompositeNode.h>
0013 #include <phool/PHNodeIOManager.h>
0014 #include <phool/PHNodeIntegrate.h>
0015 #include <phool/PHNodeIterator.h>  // for PHNodeIterator
0016 #include <phool/PHObject.h>        // for PHObject
0017 #include <phool/getClass.h>
0018 #include <phool/phool.h>  // for PHWHERE, PHReadOnly, PHRunTree
0019 #include <phool/phooldefs.h>
0020 
0021 #include <TSystem.h>
0022 
0023 #pragma GCC diagnostic push
0024 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
0025 #include <boost/algorithm/string.hpp>
0026 #pragma GCC diagnostic pop
0027 
0028 #include <cassert>
0029 #include <cstdlib>
0030 #include <iostream>  // for operator<<, basic_ostream, endl
0031 #include <utility>   // for pair
0032 #include <vector>    // for vector
0033 
0034 class TBranch;
0035 
0036 Fun4AllDstInputManager::Fun4AllDstInputManager(const std::string &name, const std::string &nodename, const std::string &topnodename)
0037   : Fun4AllInputManager(name, nodename, topnodename)
0038 {
0039   return;
0040 }
0041 
0042 Fun4AllDstInputManager::~Fun4AllDstInputManager()
0043 {
0044   delete m_IManager;
0045   delete m_RunNodeSum;
0046   return;
0047 }
0048 
0049 int Fun4AllDstInputManager::fileopen(const std::string &filenam)
0050 {
0051   Fun4AllServer *se = Fun4AllServer::instance();
0052   if (IsOpen())
0053   {
0054     std::cout << "Closing currently open file "
0055               << FileName()
0056               << " and opening " << filenam << std::endl;
0057     fileclose();
0058   }
0059   FileName(filenam);
0060   FROG frog;
0061   fullfilename = frog.location(FileName());
0062   if (Verbosity() > 0)
0063   {
0064     std::cout << Name() << ": opening file " << fullfilename << std::endl;
0065   }
0066   // sanity check - the IManager must be nullptr when this method is executed
0067   // if not something is very very wrong and we must not continue
0068   if (m_IManager)
0069   {
0070     std::cout << PHWHERE << " IManager pointer is not nullptr but " << m_IManager
0071               << std::endl;
0072     std::cout << "Send mail to off-l with this printout and the macro you used"
0073               << std::endl;
0074     std::cout << "Trying to execute IManager->print() to display more info"
0075               << std::endl;
0076     std::cout << "Code will probably segfault now" << std::endl;
0077     m_IManager->print();
0078     std::cout << "Have someone look into this problem - Exiting now" << std::endl;
0079     exit(1);
0080   }
0081   // first read the runnode if not disabled
0082   if (m_ReadRunTTree)
0083   {
0084     m_IManager = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree);
0085     if (m_IManager->isFunctional())
0086     {
0087       m_RunNode = se->getNode(RunNode, TopNodeName());
0088       m_IManager->read(m_RunNode);
0089       // get the current run number
0090       RunHeader *runheader = findNode::getClass<RunHeader>(m_RunNode, "RunHeader");
0091       if (runheader)
0092       {
0093         SetRunNumber(runheader->get_RunNumber());
0094       }
0095       // delete our internal copy of the runnode when opening subsequent files
0096       if (m_RunNodeCopy)
0097       {
0098         std::cout << PHWHERE
0099                   << " The impossible happened, we have a valid copy of the run node "
0100                   << m_RunNodeCopy->getName() << " which should be a nullptr"
0101                   << std::endl;
0102         gSystem->Exit(1);
0103       }
0104       m_RunNodeCopy = new PHCompositeNode("RUNNODECOPY");
0105       if (!m_RunNodeSum)
0106       {
0107         m_RunNodeSum = new PHCompositeNode("RUNNODESUM");
0108       }
0109       PHNodeIOManager *tmpIman = new PHNodeIOManager(fullfilename, PHReadOnly, PHRunTree);
0110       tmpIman->read(m_RunNodeCopy);
0111       delete tmpIman;
0112 
0113       PHNodeIntegrate integrate;
0114       integrate.RunNode(m_RunNode);
0115       integrate.RunSumNode(m_RunNodeSum);
0116       // run recursively over internal run node copy and integrate objects
0117       PHNodeIterator mainIter(m_RunNodeCopy);
0118       mainIter.forEach(integrate);
0119       // we do not need to keep the internal copy, keeping it would crate
0120       // problems in case a subsequent file does not contain all the
0121       // runwise objects from the previous file. Keeping this copy would then
0122       // integrate the missing object again with the old copy
0123       delete m_RunNodeCopy;
0124       m_RunNodeCopy = nullptr;
0125     }
0126     // DLW: move the delete outside the if block to cover the case where isFunctional() fails
0127     delete m_IManager;
0128   }
0129   // now open the dst node
0130   dstNode = se->getNode(InputNode(), TopNodeName());
0131   m_IManager = new PHNodeIOManager(fullfilename, PHReadOnly);
0132   if (m_IManager->isFunctional())
0133   {
0134     IsOpen(1);
0135     events_thisfile = 0;
0136     setBranches();                // set branch selections
0137     AddToFileOpened(FileName());  // add file to the list of files which were opened
0138                                   // check if our input file has a sync object or not
0139     if (ReadCacheDisabled())
0140     {
0141       m_IManager->DisableReadCache();
0142     }
0143     if (m_IManager->NodeExist(syncdefs::SYNCNODENAME))
0144     {
0145       m_HaveSyncObject = 1;
0146     }
0147     else
0148     {
0149       m_HaveSyncObject = -1;
0150     }
0151 
0152     return 0;
0153   }
0154 
0155   std::cout << PHWHERE << ": " << Name() << " Could not open file "
0156             << FileName() << std::endl;
0157   delete m_IManager;
0158   m_IManager = nullptr;
0159   return -1;
0160 }
0161 
0162 int Fun4AllDstInputManager::run(const int nevents)
0163 {
0164   if (!IsOpen())
0165   {
0166     if (FileListEmpty())
0167     {
0168       if (Verbosity() > 0)
0169       {
0170         std::cout << Name() << ": No Input file open" << std::endl;
0171       }
0172       return -1;
0173     }
0174 
0175     if (OpenNextFile())
0176     {
0177       std::cout << Name() << ": No Input file from filelist opened" << std::endl;
0178       return -1;
0179     }
0180   }
0181   if (Verbosity() > 3)
0182   {
0183     std::cout << "Getting Event from " << Name() << std::endl;
0184   }
0185 readagain:
0186   PHCompositeNode *dummy;
0187   int ncount = 0;
0188   dummy = m_IManager->read(dstNode);
0189   while (dummy)
0190   {
0191     ncount++;
0192     if (nevents > 0 && ncount >= nevents)
0193     {
0194       break;
0195     }
0196     dummy = m_IManager->read(dstNode);
0197   }
0198   if (!dummy)
0199   {
0200     fileclose();
0201     if (!OpenNextFile())
0202     {
0203       // NOLINTNEXTLINE(hicpp-avoid-goto)
0204       goto readagain;
0205     }
0206     return -1;
0207   }
0208   events_total += ncount;
0209   events_thisfile += ncount;
0210   // check if the local SubsysReco discards this event
0211   if (RejectEvent() != Fun4AllReturnCodes::EVENT_OK)
0212   {
0213     // NOLINTNEXTLINE(hicpp-avoid-goto)
0214     goto readagain;
0215   }
0216   syncobject = findNode::getClass<SyncObject>(dstNode, syncdefs::SYNCNODENAME);
0217   return 0;
0218 }
0219 
0220 int Fun4AllDstInputManager::fileclose()
0221 {
0222   if (!IsOpen())
0223   {
0224     std::cout << Name() << ": fileclose: No Input file open" << std::endl;
0225     return -1;
0226   }
0227   delete m_IManager;
0228   m_IManager = nullptr;
0229   IsOpen(0);
0230   UpdateFileList();
0231   m_HaveSyncObject = 0;
0232   return 0;
0233 }
0234 
0235 int Fun4AllDstInputManager::GetSyncObject(SyncObject **mastersync)
0236 {
0237   // here we copy the sync object from the current file to the
0238   // location pointed to by mastersync. If mastersync is a 0 pointer
0239   // the syncobject is cloned. If mastersync allready exists the content
0240   // of syncobject is copied
0241   if (!(*mastersync))
0242   {
0243     if (syncobject)
0244     {
0245       *mastersync = dynamic_cast<SyncObject *>(syncobject->CloneMe());
0246       assert(*mastersync);
0247     }
0248   }
0249   else
0250   {
0251     *(*mastersync) = *syncobject;  // copy syncobject content
0252   }
0253   return Fun4AllReturnCodes::SYNC_OK;
0254 }
0255 
0256 int Fun4AllDstInputManager::SyncIt(const SyncObject *mastersync)
0257 {
0258   if (!mastersync)
0259   {
0260     std::cout << PHWHERE << Name() << " No MasterSync object, cannot perform synchronization" << std::endl;
0261     std::cout << "Most likely your first file does not contain a SyncObject and the file" << std::endl;
0262     std::cout << "opened by the Fun4AllDstInputManager with Name " << Name() << " has one" << std::endl;
0263     std::cout << "Change your macro and use the file opened by this input manager as first input" << std::endl;
0264     std::cout << "and you will be okay. Fun4All will not process the current configuration" << std::endl
0265               << std::endl;
0266     return Fun4AllReturnCodes::SYNC_FAIL;
0267   }
0268   if (!syncobject)
0269   {
0270     std::cout << Name() << " no sync object found in this manager but synchronization needed" << std::endl;
0271     std::cout << "  Check if you have used an empty listfile. If this is not the case - please ask for help" << std::endl;
0272     std::cout << "This may be a really bad internal problem and cannot continue, exiting now " << std::endl;
0273     gSystem->Exit(1);
0274     exit(1);
0275   }
0276   int iret = syncobject->Different(mastersync);
0277   if (iret)  // what to do if files are not in sync
0278   {
0279     if (mastersync->EventNumber() == -999999)  // first file does not contain sync object
0280     {
0281       std::cout << PHWHERE << " Mastersync not filled, your first file does not contain a SyncObject" << std::endl;
0282       std::cout << "This Event will not be processed further" << std::endl;
0283     }
0284     else  // okay try to resync here
0285     {
0286       if (Verbosity() > 3)
0287       {
0288         std::cout << "Need to Resync, mastersync evt no: " << mastersync->EventNumber()
0289                   << ", this Event no: " << syncobject->EventNumber() << std::endl;
0290         std::cout << "mastersync evt counter: " << mastersync->EventNumber()
0291                   << ", this Event counter: " << syncobject->EventNumber() << std::endl;
0292         std::cout << "mastersync run number: " << mastersync->RunNumber()
0293                   << ", this run number: " << syncobject->RunNumber() << std::endl;
0294       }
0295 
0296       while (syncobject->RunNumber() < mastersync->RunNumber())
0297       {
0298         events_skipped_during_sync++;
0299         if (Verbosity() > 2)
0300         {
0301           std::cout << Name() << " Run Number: " << syncobject->RunNumber()
0302                     << ", master: " << mastersync->RunNumber()
0303                     << std::endl;
0304         }
0305         iret = ReadNextEventSyncObject();
0306         if (iret)
0307         {
0308           return iret;
0309         }
0310       }
0311       int igood = 0;
0312       if (syncobject->RunNumber() == mastersync->RunNumber())
0313       {
0314         igood = 1;
0315       }
0316       // only run up the Segment Number if run numbers are identical
0317       while (syncobject->SegmentNumber() < mastersync->SegmentNumber() && igood)
0318       {
0319         events_skipped_during_sync++;
0320         if (Verbosity() > 2)
0321         {
0322           std::cout << Name() << " Segment Number: " << syncobject->SegmentNumber()
0323                     << ", master: " << mastersync->SegmentNumber()
0324                     << std::endl;
0325         }
0326         iret = ReadNextEventSyncObject();
0327         if (iret)
0328         {
0329           return iret;
0330         }
0331       }
0332       // only run up the Event Counter if run number and segment number are identical
0333       if (syncobject->SegmentNumber() == mastersync->SegmentNumber() && syncobject->RunNumber() == mastersync->RunNumber())
0334       {
0335         igood = 1;
0336       }
0337       else
0338       {
0339         igood = 0;
0340       }
0341       while (syncobject->EventNumber() < mastersync->EventNumber() && igood)
0342       {
0343         events_skipped_during_sync++;
0344         if (Verbosity() > 2)
0345         {
0346           std::cout << Name()
0347                     << ", EventNumber: " << syncobject->EventNumber()
0348                     << ", master: " << mastersync->EventNumber()
0349                     << std::endl;
0350         }
0351         iret = ReadNextEventSyncObject();
0352         if (iret)
0353         {
0354           return iret;
0355         }
0356       }
0357       // Since up to here we only read the sync object we need to push
0358       // the current event back into the root file (subtract one from the
0359       // local root file event counter) so we can read the full event
0360       // if it syncs, if it does not sync we also read one event too many
0361       // (otherwise we cannot determine that we are "too far")
0362       // and also have to push this one back
0363       PushBackEvents(1);
0364       if (syncobject->RunNumber() > mastersync->RunNumber() ||        // check if run number too large
0365           syncobject->EventNumber() > mastersync->EventNumber() ||    // check if event counter too large
0366           syncobject->SegmentNumber() > mastersync->SegmentNumber())  // check segment number too large
0367       {
0368         // the event from first file which determines the mastersync
0369         // and which we are trying to find on this file does not exist on this file
0370         // so: return failure. This will cause the input managers to read
0371         // the next event from the input files file
0372         return Fun4AllReturnCodes::SYNC_FAIL;
0373       }
0374       // Here the event counter and segment number and run number do agree - we found the right match
0375       // now read the full event (previously we only read the sync object)
0376       PHCompositeNode *dummy;
0377       dummy = m_IManager->read(dstNode);
0378       if (!dummy)
0379       {
0380         std::cout << PHWHERE << " " << Name() << " Could not read full Event" << std::endl;
0381         std::cout << "PLEASE NOTIFY PHENIX-OFF-L and post the macro you used" << std::endl;
0382         fileclose();
0383         return Fun4AllReturnCodes::SYNC_FAIL;
0384       }
0385       iret = syncobject->Different(mastersync);  // final check if they really agree
0386       if (iret)                                  // if not things are severely wrong
0387       {
0388         std::cout << PHWHERE << " MasterSync and SyncObject of " << Name() << " are different" << std::endl;
0389         std::cout << "This Event will not be processed further, here is some debugging info:" << std::endl;
0390         std::cout << "PLEASE NOTIFY PHENIX-OFF-L and post the macro you used" << std::endl;
0391         std::cout << "MasterSync->identify:" << std::endl;
0392         mastersync->identify();
0393         std::cout << Name() << ": SyncObject->identify:" << std::endl;
0394         syncobject->identify();
0395         return Fun4AllReturnCodes::SYNC_FAIL;
0396       }
0397       if (Verbosity() > 3)
0398       {
0399         std::cout << PHWHERE << " Resynchronization successfull for " << Name() << std::endl;
0400         std::cout << "MasterSync->identify:" << std::endl;
0401         mastersync->identify();
0402         std::cout << Name() << ": SyncObject->identify:" << std::endl;
0403         syncobject->identify();
0404       }
0405     }
0406   }
0407   //    else
0408   //        {
0409   //            std::cout << "No Need to Resync" << std::endl;
0410   //        }
0411   return Fun4AllReturnCodes::SYNC_OK;
0412 }
0413 
0414 int Fun4AllDstInputManager::ReadNextEventSyncObject()
0415 {
0416 readnextsync:
0417   static int readfull = 0;  // for some reason all the input managers need to see the same (I think, should look at this at some point)
0418   if (!m_IManager)          // in case the old file was exhausted and there is no new file opened
0419   {
0420     return Fun4AllReturnCodes::SYNC_FAIL;
0421   }
0422   if (syncbranchname.empty())
0423   {
0424     readfull = 1;  // we need to read a full event to set the root branches to phool nodes right when a new file has been opened
0425     std::map<std::string, TBranch *>::const_iterator bIter;
0426     for (bIter = m_IManager->GetBranchMap()->begin(); bIter != m_IManager->GetBranchMap()->end(); ++bIter)
0427     {
0428       if (Verbosity() > 2)
0429       {
0430         std::cout << Name() << ": branch: " << bIter->first << std::endl;
0431       }
0432       std::string delimeters = phooldefs::branchpathdelim;  // + phooldefs::legacypathdelims;
0433       std::vector<std::string> splitvec;
0434       boost::split(splitvec, bIter->first, boost::is_any_of(delimeters));
0435       for (auto &ia : splitvec)  // -1 so we skip the node name
0436       {
0437         if (ia == syncdefs::SYNCNODENAME)
0438         {
0439           syncbranchname = bIter->first;
0440           break;
0441         }
0442       }
0443       if (!syncbranchname.empty())
0444       {
0445         break;
0446       }
0447     }
0448     if (syncbranchname.empty())
0449     {
0450       std::cout << PHWHERE << "Could not locate Sync Branch" << std::endl;
0451       std::cout << "Please check for it in the following list of branch names and" << std::endl;
0452       std::cout << "PLEASE NOTIFY PHENIX-OFF-L and post the macro you used" << std::endl;
0453       for (bIter = m_IManager->GetBranchMap()->begin(); bIter != m_IManager->GetBranchMap()->end(); ++bIter)
0454       {
0455         std::cout << bIter->first << std::endl;
0456       }
0457       return Fun4AllReturnCodes::SYNC_FAIL;
0458     }
0459   }
0460   size_t EventOnDst = 0;
0461   int itest = 0;
0462   if (!readfull)
0463   {
0464     // if all files are exhausted, the IManager is deleted and set to nullptr
0465     // so check if IManager is valid before getting a new event
0466     if (m_IManager)
0467     {
0468       EventOnDst = m_IManager->getEventNumber();  // this returns the next number of the event
0469       itest = m_IManager->readSpecific(EventOnDst, syncbranchname);
0470     }
0471     else
0472     {
0473       if (Verbosity() > 2)
0474       {
0475         std::cout << Name() << ": File exhausted while resyncing" << std::endl;
0476       }
0477       return Fun4AllReturnCodes::SYNC_FAIL;
0478     }
0479   }
0480   else
0481   {
0482     if (m_IManager->read(dstNode))
0483     {
0484       itest = 1;
0485     }
0486     else
0487     {
0488       itest = 0;
0489     }
0490   }
0491   if (!itest)
0492   {
0493     if (Verbosity() > 2)
0494     {
0495       std::cout << Name() << ": File exhausted while resyncing" << std::endl;
0496     }
0497     fileclose();
0498     if (OpenNextFile())
0499     {
0500       return Fun4AllReturnCodes::SYNC_FAIL;
0501     }
0502     syncbranchname.clear();  // clear the sync branch name, who knows - it might be different on new file
0503     // NOLINTNEXTLINE(hicpp-avoid-goto)
0504     goto readnextsync;
0505   }
0506   if (!readfull)
0507   {
0508     EventOnDst++;
0509     m_IManager->setEventNumber(EventOnDst);  // update event number in phool io manager
0510   }
0511   else
0512   {
0513     readfull = 0;
0514   }
0515   return 0;
0516 }
0517 
0518 int Fun4AllDstInputManager::BranchSelect(const std::string &branch, const int iflag)
0519 {
0520   if (IsOpen())
0521   {
0522     std::cout << "BranchSelect(\"" << branch << "\", " << iflag
0523               << ") : Input branches can only selected for reading before fileopen is called proceeding without input branch selection" << std::endl;
0524     return -1;
0525   }
0526   // if iflag > 0 the branch is set to read
0527   // if iflag = 0, the branch is set to NOT read
0528   // if iflag < 0 the branchname is erased from our internal branch read map
0529   // this does not have any effect on phool yet
0530   if (iflag < 0)
0531   {
0532     std::map<const std::string, int>::iterator branchiter;
0533     branchiter = branchread.find(branch);
0534     if (branchiter != branchread.end())
0535     {
0536       branchread.erase(branchiter);
0537     }
0538     return 0;
0539   }
0540   int readit = 0;
0541   if (iflag > 0)
0542   {
0543     if (Verbosity() > 1)
0544     {
0545       std::cout << "Setting Root Tree Branch: " << branch << " to read" << std::endl;
0546     }
0547     readit = 1;
0548   }
0549   else
0550   {
0551     if (Verbosity() > 1)
0552     {
0553       std::cout << "Setting Root Tree Branch: " << branch << " to NOT read" << std::endl;
0554     }
0555   }
0556   branchread[branch] = readit;
0557   return 0;
0558 }
0559 
0560 int Fun4AllDstInputManager::setBranches()
0561 {
0562   if (m_IManager)
0563   {
0564     if (!branchread.empty())
0565     {
0566       std::map<const std::string, int>::const_iterator branchiter;
0567       for (branchiter = branchread.begin(); branchiter != branchread.end(); ++branchiter)
0568       {
0569         m_IManager->selectObjectToRead(branchiter->first, branchiter->second);
0570         if (Verbosity() > 0)
0571         {
0572           std::cout << branchiter->first << " set to " << branchiter->second << std::endl;
0573         }
0574       }
0575       // protection against switching off the sync variables
0576       // only implemented in the Sync Manager
0577       setSyncBranches(m_IManager);
0578     }
0579   }
0580   else
0581   {
0582     std::cout << PHWHERE << " " << Name() << ": You can only call this function after a file has been opened" << std::endl;
0583     std::cout << "Do not worry, the branches will be set as soon as you open a file" << std::endl;
0584     return -1;
0585   }
0586   return 0;
0587 }
0588 
0589 int Fun4AllDstInputManager::setSyncBranches(PHNodeIOManager *IMan)
0590 {
0591   // protection against switching off the sync variables
0592   for (auto &i : syncdefs::SYNCVARS)
0593   {
0594     IMan->selectObjectToRead(i, true);
0595   }
0596   return 0;
0597 }
0598 
0599 void Fun4AllDstInputManager::Print(const std::string &what) const
0600 {
0601   if (what == "ALL" || what == "BRANCH")
0602   {
0603     // loop over the map and print out the content (name and location in memory)
0604     std::cout << "--------------------------------------" << std::endl
0605               << std::endl;
0606     std::cout << "List of selected branches in Fun4AllDstInputManager " << Name() << ":" << std::endl;
0607 
0608     std::map<const std::string, int>::const_iterator iter;
0609     for (iter = branchread.begin(); iter != branchread.end(); ++iter)
0610     {
0611       std::cout << iter->first << " is switched ";
0612       if (iter->second)
0613       {
0614         std::cout << "ON";
0615       }
0616       else
0617       {
0618         std::cout << "OFF";
0619       }
0620       std::cout << std::endl;
0621     }
0622   }
0623   if ((what == "ALL" || what == "PHOOL") && m_IManager)
0624   {
0625     // loop over the map and print out the content (name and location in memory)
0626     std::cout << "--------------------------------------" << std::endl
0627               << std::endl;
0628     std::cout << "PHNodeIOManager print in Fun4AllDstInputManager " << Name() << ":" << std::endl;
0629     m_IManager->print();
0630   }
0631   Fun4AllInputManager::Print(what);
0632   return;
0633 }
0634 
0635 int Fun4AllDstInputManager::PushBackEvents(const int i)
0636 {
0637   if (m_IManager)
0638   {
0639     unsigned EventOnDst = m_IManager->getEventNumber();
0640     EventOnDst -= static_cast<unsigned>(i);
0641     m_IManager->setEventNumber(EventOnDst);
0642     return 0;
0643   }
0644   std::cout << PHWHERE << Name() << ": could not push back events, Imanager is NULL"
0645             << " probably the dst is not open yet (you need to call fileopen or run 1 event for lists)" << std::endl;
0646   return -1;
0647 }
0648 
0649 int Fun4AllDstInputManager::HasSyncObject() const
0650 {
0651   if (m_HaveSyncObject)
0652   {
0653     return m_HaveSyncObject;
0654   }
0655   if (IsOpen())
0656   {
0657     std::cout << PHWHERE << "HasSyncObject() not initialized check the calling order" << std::endl;
0658     gSystem->Exit(1);
0659     exit(1);
0660   }
0661   return 0;
0662 }