Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-18 09:17:54

0001 #include "XingShiftCal.h"
0002 
0003 #include <cdbobjects/CDBTTree.h>
0004 
0005 #include <fun4all/DBInterface.h>
0006 
0007 #include <fun4all/Fun4AllReturnCodes.h>
0008 
0009 #include <phool/getClass.h>
0010 #include <phool/phool.h>
0011 #include <phool/recoConsts.h>
0012 
0013 #include <Event/Event.h>
0014 #include <Event/EventTypes.h>
0015 #include <Event/packet.h>
0016 
0017 #include <TCanvas.h>
0018 #include <TH1.h>
0019 
0020 #include <odbc++/resultset.h>
0021 #include <odbc++/statement.h>
0022 
0023 #include <format>
0024 #include <iostream>
0025 #include <memory>
0026 
0027 XingShiftCal::XingShiftCal(const std::string &name, const int poverwriteSpinEntry)
0028   : SubsysReco(name)
0029   , nevt(0)
0030   , overwriteSpinEntry(poverwriteSpinEntry)
0031 {
0032   // overwriteSpinEntry = poverwriteSpinEntry;
0033 
0034   for (auto &scalercount : scalercounts)
0035   {
0036     for (unsigned long &j : scalercount)
0037     {
0038       j = 0;
0039     }
0040   }
0041 
0042   std::cout << "XingShiftCal::XingShiftCal(const std::string &name) Calling ctor" << std::endl;
0043 }
0044 
0045 int XingShiftCal::Init(PHCompositeNode * /*topNode*/)
0046 {
0047   std::cout << "XingShiftCal::Init(PHCompositeNode *topNode) Initializing" << std::endl;
0048   preset_pattern_blue["111x111_P1"] = "+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+*********";
0049   preset_pattern_yellow["111x111_P1"] = "++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++-*********";
0050   preset_pattern_blue["111x111_P2"] = "-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-*********";
0051   preset_pattern_yellow["111x111_P2"] = "++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++-*********";
0052   preset_pattern_blue["111x111_P3"] = "+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+*********";
0053   preset_pattern_yellow["111x111_P3"] = "--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+*********";
0054   preset_pattern_blue["111x111_P4"] = "-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-*********";
0055   preset_pattern_yellow["111x111_P4"] = "--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+*********";
0056   preset_pattern_blue["111x111_P5"] = "++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++-*********";
0057   preset_pattern_yellow["111x111_P5"] = "+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+*********";
0058   preset_pattern_blue["111x111_P6"] = "--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+*********";
0059   preset_pattern_yellow["111x111_P6"] = "+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+--+-++-+-+-+--+-+-+-++-+*********";
0060   preset_pattern_blue["111x111_P7"] = "++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++-*********";
0061   preset_pattern_yellow["111x111_P7"] = "-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-*********";
0062   preset_pattern_blue["111x111_P8"] = "--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--++--+*********";
0063   preset_pattern_yellow["111x111_P8"] = "-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-++-+--+-+-+-++-+-+-+--+-*********";
0064 
0065   return Fun4AllReturnCodes::EVENT_OK;
0066 }
0067 
0068 int XingShiftCal::InitRun(PHCompositeNode * /*topNode*/)
0069 {
0070   // std::cout << "XingShiftCal::InitRun(PHCompositeNode *topNode) Initializing for Run XXX" << std::endl;
0071 
0072   recoConsts *rc = recoConsts::instance();
0073   runnumber = rc->get_IntFlag("RUNNUMBER");
0074   return Fun4AllReturnCodes::EVENT_OK;
0075 }
0076 
0077 int XingShiftCal::process_event(PHCompositeNode *topNode)
0078 {
0079   if (done == 1)
0080   {
0081     return Fun4AllReturnCodes::EVENT_OK;
0082   }
0083   // std::cout << "XingShiftCal::process_event(PHCompositeNode *topNode) Processing Event" << std::endl;
0084   Event *evt = findNode::getClass<Event>(topNode, "PRDF");
0085 
0086   if (evt->getEvtType() == BEGRUNEVENT)
0087   {
0088     //================ BeginRunEvent packets ================//
0089     pBluePol = evt->getPacket(packet_BLUEPOL);
0090     pYellPol = evt->getPacket(packet_YELLPOL);
0091 
0092     pBlueIntPattern = evt->getPacket(packet_BLUEINTPATTERN);
0093     pYellIntPattern = evt->getPacket(packet_YELLINTPATTERN);
0094     pBluePolPattern = evt->getPacket(packet_BLUEPOLPATTERN);
0095     pYellPolPattern = evt->getPacket(packet_YELLPOLPATTERN);
0096 
0097     pBlueAsym = evt->getPacket(packet_BLUEASYM);
0098     pYellAsym = evt->getPacket(packet_YELLASYM);
0099 
0100     pBlueFillNumber = evt->getPacket(packet_BLUEFILLNUMBER);
0101     pYellFillNumber = evt->getPacket(packet_YELLFILLNUMBER);
0102     //=======================================================//
0103 
0104     //========= Get beam polarizations ==============//
0105     polBlue = -999;
0106     polBlueErr = -999;
0107     if (pBluePol)
0108     {
0109       polBlue = pBluePol->iValue(0) / 10000.0;
0110       polBlueErr = pBluePol->iValue(1) / 10000.0;
0111       delete pBluePol;
0112     }
0113 
0114     polYellow = -999;
0115     polYellowErr = -999;
0116     if (pYellPol)
0117     {
0118       polYellow = pYellPol->iValue(0) / 10000.0;
0119       polYellowErr = pYellPol->iValue(1) / 10000.0;
0120       delete pYellPol;
0121     }
0122     //==========================================================//
0123 
0124     //============== Get intended spin patterns from buckets ==============//
0125     // there are 360 buckets for 120 bunches
0126 
0127     if (pBlueIntPattern && pBluePolPattern)
0128     {
0129       for (int i = 0; i < 360; i += 3)
0130       {
0131         blueFillPattern[i / 3] = pBlueIntPattern->iValue(i);
0132         if (pBlueIntPattern->iValue(i))
0133         {
0134           blueSpinPattern[i / 3] = pBluePolPattern->iValue(i);
0135         }
0136         else
0137         {
0138           blueSpinPattern[i / 3] = 10;
0139         }
0140       }
0141       delete pBlueIntPattern;
0142       delete pBluePolPattern;
0143     }
0144 
0145     if (pYellIntPattern && pYellPolPattern)
0146     {
0147       for (int i = 0; i < 360; i += 3)
0148       {
0149         yellFillPattern[i / 3] = pYellIntPattern->iValue(i);
0150         if (pYellIntPattern->iValue(i))
0151         {
0152           yellSpinPattern[i / 3] = pYellPolPattern->iValue(i);
0153         }
0154         else
0155         {
0156           yellSpinPattern[i / 3] = 10;
0157         }
0158       }
0159       delete pYellIntPattern;
0160       delete pYellPolPattern;
0161     }
0162     //=======================================================================//
0163 
0164     //============== Get pC spin patterns from buckets ==============//
0165 
0166     // Get bunch asymmetries for measured spin pattern
0167     // there are 360 buckets for 120 bunches
0168     if (pBlueAsym)
0169     {
0170       for (int i = 0; i < 360; i += 3)
0171       {
0172         float blueAsyms = pBlueAsym->iValue(i) / 10000.0;
0173         float blueAsymsErr = pBlueAsym->iValue(i + 360) / 10000.0;
0174 
0175         float bluebot = blueAsyms - blueAsymsErr;
0176         float bluetop = blueAsyms + blueAsymsErr;
0177 
0178         if (blueAsyms != 0 || bluebot != 0 || bluetop != 0)
0179         {
0180           if (bluebot > 0 && bluetop > 0)
0181           {
0182             bluePcSpinPattern[i / 3] = 1;
0183           }
0184           else if (bluebot < 0 && bluetop < 0)
0185           {
0186             bluePcSpinPattern[i / 3] = -1;
0187           }
0188           else if (bluebot <= 0 && bluetop >= 0)
0189           {
0190             bluePcSpinPattern[i / 3] = 0;
0191           }
0192         }
0193         else
0194         {
0195           bluePcSpinPattern[i / 3] = 10;
0196         }
0197       }
0198       delete pBlueAsym;
0199     }
0200 
0201     if (pYellAsym)
0202     {
0203       for (int i = 0; i < 360; i += 3)
0204       {
0205         float yellAsyms = pYellAsym->iValue(i) / 10000.0;
0206         float yellAsymsErr = pYellAsym->iValue(i + 360) / 10000.0;
0207 
0208         float yellbot = yellAsyms - yellAsymsErr;
0209         float yelltop = yellAsyms + yellAsymsErr;
0210 
0211         if (yellAsyms != 0 || yellbot != 0 || yelltop != 0)
0212         {
0213           if (yellbot > 0 && yelltop > 0)
0214           {
0215             yellPcSpinPattern[i / 3] = 1;
0216           }
0217           else if (yellbot < 0 && yelltop < 0)
0218           {
0219             yellPcSpinPattern[i / 3] = -1;
0220           }
0221           else if (yellbot <= 0 && yelltop >= 0)
0222           {
0223             yellPcSpinPattern[i / 3] = 0;
0224           }
0225         }
0226         else
0227         {
0228           yellPcSpinPattern[i / 3] = 10;
0229         }
0230       }
0231       delete pYellAsym;
0232     }
0233     //=======================================================================//
0234 
0235     //============== Get fill number ==============//
0236     fillnumberBlue = 0;
0237     fillnumberYellow = 0;
0238     if (pBlueFillNumber)
0239     {
0240       fillnumberBlue = pBlueFillNumber->iValue(0);
0241       delete pBlueFillNumber;
0242     }
0243     if (pYellFillNumber)
0244     {
0245       fillnumberYellow = pYellFillNumber->iValue(0);
0246       delete pYellFillNumber;
0247     }
0248     //=======================================================//
0249   }
0250   else if (evt->getEvtType() == DATAEVENT)
0251   {
0252     p = evt->getPacket(packet_GL1);
0253     int bunchnr = p->lValue(0, "BunchNumber");
0254 
0255     for (int i = 0; i < NTRIG; i++)
0256     {
0257       // 2nd arg of lValue: 0 is raw trigger count, 1 is live trigger count, 2 is scaled trigger count
0258       long gl1pscaler = p->lValue(i, "GL1PLIVE");
0259       scalercounts[i][bunchnr] = gl1pscaler;
0260     }
0261     delete p;
0262   }
0263 
0264   if (nevt > threshold)
0265   {
0266     Calibrate();
0267     if (success)
0268     {
0269       done = 1;
0270     }
0271     else
0272     {
0273       threshold += threshold;
0274     }
0275   }
0276 
0277   if (nevt > evtcap)
0278   {
0279     done = 1;
0280   }
0281 
0282   nevt++;
0283 
0284   return Fun4AllReturnCodes::EVENT_OK;
0285 }
0286 
0287 int XingShiftCal::End(PHCompositeNode * /*topNode*/)
0288 {
0289   std::cout << "XingShiftCal::End(PHCompositeNode *topNode) This is the End..." << std::endl;
0290 
0291   if (done)
0292   {
0293     // if (!success){
0294     Calibrate(1);
0295     //}
0296     // CommitConstantsToFile();
0297   }
0298   else
0299   {
0300     success = false;
0301     std::cout << "Not enough statistics. Did not calibrate." << std::endl;
0302   }
0303 
0304   const std::string cdbfname = std::format("SPIN-{:08}_crossingshiftCDBTTree.root", runnumber);
0305   WriteToCDB(cdbfname);
0306   CommitToSpinDB();
0307 
0308   if (commitSuccessCDB)
0309   {
0310     std::cout << "Commit to CDB : SUCCESS" << std::endl;
0311   }
0312   else
0313   {
0314     std::cout << "Commit to CDB : FAILURE" << std::endl;
0315   }
0316 
0317   if (commitSuccessSpinDB)
0318   {
0319     std::cout << "Commit to SpinDB : SUCCESS" << std::endl;
0320   }
0321   else
0322   {
0323     std::cout << "Commit to SpinDB : FAILURE" << std::endl;
0324   }
0325 
0326   return Fun4AllReturnCodes::EVENT_OK;
0327 }
0328 
0329 int XingShiftCal::Calibrate(const int final)
0330 {
0331   CalculateCrossingShift(xingshift, scalercounts, success);
0332   if (!success)
0333   {
0334     std::cout << "CROSSING CALIBRATION FAILED." << std::endl;
0335     if (final)
0336     {
0337       std::cout << "DONE CALIBRATING." << std::endl;
0338     }
0339     return 0;
0340   }
0341 
0342   if (final)
0343   {
0344     // ostringstream comment;
0345     std::cout << "CROSSING CALIBRATION SUCCESS. XINGSHIFT: " << xingshift << std::endl;
0346     std::cout << "DONE CALIBRATING." << std::endl;
0347     // AddComment(comment.str());
0348   }
0349 
0350   return 0;
0351 }
0352 
0353 int XingShiftCal::CalculateCrossingShift(int &xing, uint64_t counts[NTRIG][NBUNCHES], bool &succ)
0354 {
0355   succ = false;
0356   int shift_array[NTRIG] = {0};
0357 
0358   int trig_inactive_array[NTRIG] = {0};
0359 
0360   int last_active_index = 0;
0361 
0362   int _temp;
0363   for (int itrig = 0; itrig < NTRIG; itrig++)
0364   {
0365     long long _counts = 0;
0366     for (int ii = 0; ii < NBUNCHES; ii++)
0367     {
0368       _counts += counts[itrig][ii];
0369     }
0370 
0371     if (_counts < 10000)
0372     {
0373       trig_inactive_array[itrig] = 1;
0374     }
0375     else
0376     {
0377       last_active_index = itrig;
0378     }
0379 
0380     long long abort_sum_prev = _counts;
0381 
0382     _temp = 0;
0383     for (int ishift = 0; ishift < NBUNCHES; ishift++)
0384     {
0385       long long abort_sum = 0;
0386       for (int iunfillbunch = 0; iunfillbunch < NBUNCHES; iunfillbunch++)
0387       {
0388         if (blueFillPattern[iunfillbunch] && yellFillPattern[iunfillbunch])
0389         {
0390           continue;
0391         }
0392         int shiftbunch = iunfillbunch - ishift;
0393         if (shiftbunch < 0)
0394         {
0395           shiftbunch = 120 + shiftbunch;
0396         }
0397         abort_sum += counts[itrig][(shiftbunch) % NBUNCHES];
0398       }
0399       if (abort_sum < abort_sum_prev)
0400       {
0401         abort_sum_prev = abort_sum;
0402         _temp = ishift;
0403       }
0404     }
0405 
0406     shift_array[itrig] = _temp;
0407   }
0408 
0409   for (int itrig = 0; itrig < NTRIG; itrig++)
0410   {
0411     // if not matching for all trigger selections used, fails
0412     if (!trig_inactive_array[itrig])
0413     {
0414       if (shift_array[itrig] == shift_array[last_active_index])
0415       {
0416         xing = shift_array[itrig];
0417         succ = true;
0418       }
0419       else
0420       {
0421         xing = -999;
0422         succ = false;
0423         return 0;
0424       }
0425     }
0426   }
0427 
0428   // succ = true;
0429   return 0;
0430 }
0431 
0432 int XingShiftCal::WriteToCDB(const std::string &fname)
0433 {
0434   std::cout << "XingShiftCal::WriteToCDB()" << std::endl;
0435   int xing_correction_offset = 0;
0436   if (success)
0437   {
0438     xing_correction_offset = xingshift;
0439     CDBTTree *cdbttree = new CDBTTree(fname);
0440     cdbttree->SetSingleIntValue("crossingshift", xing_correction_offset);
0441     cdbttree->CommitSingle();
0442     // cdbttree->Print();
0443     cdbttree->WriteCDBTTree();
0444     delete cdbttree;
0445 
0446     commitSuccessCDB = 1;
0447   }
0448   else
0449   {
0450     // if (verbosity) {
0451     std::cout << "no successful calibration, do not commit crossing shift to CDB" << std::endl;
0452     //}
0453     commitSuccessCDB = 0;
0454   }
0455 
0456   return 0;
0457 }
0458 
0459 // Commit to spinDB ported from PHENIX
0460 int XingShiftCal::CommitToSpinDB()
0461 {
0462   std::cout << "XingShiftCal::CommitPatternToSpinDB()" << std::endl;
0463 
0464   if (runnumber == 0)
0465   {
0466     std::cout << "Run doesn't exist" << std::endl;
0467     commitSuccessSpinDB = 0;
0468     return 0;
0469   }
0470 
0471   if (fillnumberBlue != fillnumberYellow)
0472   {
0473     std::cout << "fillnumber is wrong : fillnumberBlue = " << fillnumberBlue
0474               << "fillnumberYellow = " << fillnumberYellow << std::endl;
0475     commitSuccessSpinDB = 0;
0476     return 0;
0477   }
0478 
0479   int xing_correction_offset = -999;
0480   if (success)
0481   {
0482     xing_correction_offset = xingshift;
0483   }
0484   else
0485   {
0486     // if (verbosity) {
0487     std::cout << "no successful calibration, commit crossing shift -999 to spinDB" << std::endl;
0488 
0489     //}
0490     commitSuccessSpinDB = 0;
0491     // return 0;
0492   }
0493 
0494   // prepare values for db
0495   unsigned int qa_level = 0xffff;
0496 
0497   //=============== connect to daq db to get gl1p scalers ===============
0498   std::string daqdbname = "daq";
0499 
0500   std::string sqlGL1PSelect = "SELECT index, bunch, scaled FROM gl1_pscalers WHERE runnumber = " + std::to_string(runnumber);
0501   odbc::Statement *stmtGL1PSelect = DBInterface::instance()->getStatement(daqdbname);
0502   std::unique_ptr<odbc::ResultSet> rsGL1P;
0503   try
0504   {
0505     rsGL1P = std::unique_ptr<odbc::ResultSet>(stmtGL1PSelect->executeQuery(sqlGL1PSelect));
0506   }
0507   catch (odbc::SQLException &eGL1P)
0508   {
0509     std::cout << PHWHERE
0510               << " Exception caught at XingShiftCal::CommitPatternToSpinDB when querying DAQ DB" << std::endl;
0511     std::cout << "Message: " << eGL1P.getMessage() << std::endl;
0512     // commitSuccessSpinDB = 0;
0513     return 0;
0514   }
0515 
0516   while (rsGL1P->next())
0517   {
0518     int index = rsGL1P->getInt("index");
0519     int bunch = rsGL1P->getInt("bunch");
0520     // MBD NS
0521     if (index == 0)
0522     {
0523       mbdns[bunch] = rsGL1P->getInt("scaled");
0524     }
0525     else if (index == 1)
0526     {
0527       mbdvtx[bunch] = rsGL1P->getInt("scaled");
0528     }
0529     else if (index == 5)
0530     {
0531       zdcns[bunch] = rsGL1P->getInt("scaled");
0532     }
0533   }
0534 
0535   // =======================================================
0536 
0537   // if (verbosity) {
0538   std::cout << "polb = " << polBlue << " +- " << polBlueErr
0539             << std::endl
0540             << "poly = " << polYellow << " +- " << polYellowErr
0541             << std::endl;
0542   //}
0543 
0544   if (true /*0 && verbosity*/)
0545   {
0546     for (int ibeam = 0; ibeam < 2; ibeam++)
0547     {
0548       if (!ibeam)
0549       {
0550         std::cout << "spinpatternblue = {";
0551       }
0552       else
0553       {
0554         std::cout << "spinpatternyellow = {";
0555       }
0556       for (int icross = 0; icross < NBUNCHES; icross++)
0557       {
0558         if (!ibeam)
0559         {
0560           std::cout << blueSpinPattern[icross] << ",";
0561         }
0562         else
0563         {
0564           std::cout << yellSpinPattern[icross] << ",";
0565         }
0566       }
0567       std::cout << "\b}\n";
0568     }
0569   }
0570 
0571   if (true)
0572   {
0573     for (int i = 0; i < 3; i++)
0574     {
0575       if (i == 0)
0576       {
0577         std::cout << "mbdns = {";
0578       }
0579       else if (i == 1)
0580       {
0581         std::cout << "mbdvtx = {";
0582       }
0583       else if (i == 2)
0584       {
0585         std::cout << "zdcns = {";
0586       }
0587       for (int icross = 0; icross < NBUNCHES; icross++)
0588       {
0589         if (i == 0)
0590         {
0591           std::cout << mbdns[icross] << ",";
0592         }
0593         else if (i == 1)
0594         {
0595           std::cout << mbdvtx[icross] << ",";
0596         }
0597         else if (i == 2)
0598         {
0599           std::cout << zdcns[icross] << ",";
0600         }
0601       }
0602       std::cout << "\b}\n";
0603     }
0604   }
0605 
0606   //================ connect to spin db ====================
0607   std::string dbname = "spinDB_write";
0608   std::string dbtable = "spin";
0609   // if (verbosity) cout << "opened spin DB connection" << endl;
0610 
0611   // check if this run already exists in spin_oncal
0612   bool runExists = false;
0613   std::string sqlSpinSelect = "SELECT runnumber, qa_level FROM " + dbtable + " WHERE runnumber = " + std::to_string(runnumber) + " AND qa_level = " + std::to_string(qa_level);
0614 
0615   // if (verbosity) cout<<sqlSpinSelect.str()<<endl;
0616   odbc::Statement *stmtSpinSelect = DBInterface::instance()->getStatement(dbname);
0617   std::unique_ptr<odbc::ResultSet> rsSpin;
0618   try
0619   {
0620     rsSpin = std::unique_ptr<odbc::ResultSet>(stmtSpinSelect->executeQuery(sqlSpinSelect));
0621   }
0622   catch (odbc::SQLException &e)
0623   {
0624     std::cout << PHWHERE
0625               << " Exception caught at XingShiftCal::CommitPatternToSpinDB when querying spin DB" << std::endl;
0626     std::cout << "Message: " << e.getMessage() << std::endl;
0627     commitSuccessSpinDB = 0;
0628     return 0;
0629   }
0630   if (rsSpin->next())
0631   {
0632     if (true /*verbosity*/)
0633     {
0634       std::cout << "run " << runnumber << " exists in " << dbtable
0635                 << ", ready to UPDATE" << std::endl;
0636     }
0637     runExists = true;
0638   }
0639   else
0640   {
0641     if (true /*verbosity*/)
0642     {
0643       std::cout << "run " << runnumber << " NOT exists in " << dbtable
0644                 << ", ready to INSERT" << std::endl;
0645     }
0646   }
0647 
0648   if (runExists && !overwriteSpinEntry)
0649   {
0650     std::cout << "BUT overwriteSpinEntry = " << overwriteSpinEntry << std::endl;
0651     std::cout << "XingShiftCal is NOT going to UPDATE the entry" << std::endl;
0652     commitSuccessSpinDB = 0;
0653     return 0;
0654   }
0655 
0656   // prepare insert sql
0657   std::ostringstream sql;
0658   if (runExists)
0659   {
0660     // SQLArrayConstF(float x, int n)
0661     sql << "UPDATE " << dbtable
0662         << " SET fillnumber = " << fillnumberBlue << ", "
0663         << "polarblue = " << SQLArrayConstF(polBlue, NBUNCHES) << ", "
0664         << "polarblueerror = " << SQLArrayConstF(polBlueErr, NBUNCHES) << ", "
0665         << "polaryellow = " << SQLArrayConstF(polYellow, NBUNCHES) << ", "
0666         << "polaryellowerror = " << SQLArrayConstF(polYellowErr, NBUNCHES) << ", "
0667         << "crossingshift = " << xing_correction_offset << ", ";
0668     sql << "spinpatternblue = '{";
0669     for (int icross = 0; icross < NBUNCHES; icross++)
0670     {
0671       sql << blueSpinPattern[icross];
0672       if (icross < NBUNCHES - 1)
0673       {
0674         sql << ",";
0675       }
0676     }
0677     sql << "}'";
0678     sql << ", spinpatternyellow = '{";
0679     for (int icross = 0; icross < NBUNCHES; icross++)
0680     {
0681       sql << yellSpinPattern[icross];
0682       if (icross < NBUNCHES - 1)
0683       {
0684         sql << ",";
0685       }
0686     }
0687     sql << "}'";
0688 
0689     sql << ", mbdns = '{";
0690     for (int icross = 0; icross < NBUNCHES; icross++)
0691     {
0692       sql << mbdns[icross];
0693       if (icross < NBUNCHES - 1)
0694       {
0695         sql << ",";
0696       }
0697     }
0698     sql << "}'";
0699 
0700     sql << ", mbdvtx = '{";
0701     for (int icross = 0; icross < NBUNCHES; icross++)
0702     {
0703       sql << mbdvtx[icross];
0704       if (icross < NBUNCHES - 1)
0705       {
0706         sql << ",";
0707       }
0708     }
0709     sql << "}'";
0710 
0711     sql << ", zdcns = '{";
0712     for (int icross = 0; icross < NBUNCHES; icross++)
0713     {
0714       sql << zdcns[icross];
0715       if (icross < NBUNCHES - 1)
0716       {
0717         sql << ",";
0718       }
0719     }
0720     sql << "}'";
0721 
0722     sql << " WHERE runnumber = " << runnumber
0723         << " AND qa_level = " << qa_level
0724         << ";";
0725   }
0726   else
0727   {
0728     sql << "INSERT INTO " << dbtable;
0729     sql << " (runnumber, fillnumber, polarblue, polarblueerror, polaryellow, polaryellowerror, crossingshift, spinpatternblue, spinpatternyellow, mbdns, mbdvtx, zdcns, qa_level) VALUES (";
0730     sql << runnumber << ", "
0731         << fillnumberBlue << ", "
0732         << SQLArrayConstF(polBlue, NBUNCHES) << ", "
0733         << SQLArrayConstF(polBlueErr, NBUNCHES) << ", "
0734         << SQLArrayConstF(polYellow, NBUNCHES) << ", "
0735         << SQLArrayConstF(polYellowErr, NBUNCHES) << ", "
0736         << xing_correction_offset << ", ";
0737     sql << "'{";
0738     for (int icross = 0; icross < NBUNCHES; icross++)
0739     {
0740       sql << blueSpinPattern[icross];
0741       if (icross < NBUNCHES - 1)
0742       {
0743         sql << ",";
0744       }
0745     }
0746     sql << "}'";
0747     sql << ", '{";
0748     for (int icross = 0; icross < NBUNCHES; icross++)
0749     {
0750       sql << yellSpinPattern[icross];
0751       if (icross < NBUNCHES - 1)
0752       {
0753         sql << ",";
0754       }
0755     }
0756     sql << "}'";
0757     sql << ", '{";
0758     for (int icross = 0; icross < NBUNCHES; icross++)
0759     {
0760       sql << mbdns[icross];
0761       if (icross < NBUNCHES - 1)
0762       {
0763         sql << ",";
0764       }
0765     }
0766     sql << "}'";
0767     sql << ", '{";
0768     for (int icross = 0; icross < NBUNCHES; icross++)
0769     {
0770       sql << mbdvtx[icross];
0771       if (icross < NBUNCHES - 1)
0772       {
0773         sql << ",";
0774       }
0775     }
0776     sql << "}'";
0777     sql << ", '{";
0778     for (int icross = 0; icross < NBUNCHES; icross++)
0779     {
0780       sql << zdcns[icross];
0781       if (icross < NBUNCHES - 1)
0782       {
0783         sql << ",";
0784       }
0785     }
0786     sql << "}'";
0787 
0788     sql << ", " << qa_level << ");";
0789   }
0790   if (true /*verbosity*/)
0791   {
0792     std::cout << sql.str() << std::endl;
0793   }
0794 
0795   // exec sql
0796   rsSpin.reset();
0797   odbc::Statement *stmtSpin = DBInterface::instance()->getStatement(dbname);
0798   try
0799   {
0800     stmtSpin->executeUpdate(sql.str());
0801   }
0802   catch (odbc::SQLException &e)
0803   {
0804     std::cout << PHWHERE
0805               << " Exception caught at XingShiftCal::CommitPatternToSpinDB when insert into spin DB" << std::endl;
0806     std::cout << "Message: " << e.getMessage() << std::endl;
0807     commitSuccessSpinDB = 0;
0808     return 0;
0809   }
0810 
0811   // if (verbosity) cout<<"spin db done"<<endl;
0812   commitSuccessSpinDB = 1;
0813 
0814   // ========== Do spin db qa here =========== //
0815   SpinDBQA();
0816   // ========================================= //
0817 
0818   return 0;
0819 }
0820 
0821 int XingShiftCal::SpinDBQA()
0822 {
0823   // prepare values for db
0824   unsigned int qa_level = 0xffff;
0825 
0826   //================ connect to spin db ====================
0827   std::string dbname = "spinDB";
0828   std::string dbtable = "spin";
0829 
0830   // check if this run already exists in spin_oncal and get badrun value if it exists
0831   bool runExists = false;
0832   int prevbadrunval = 0;
0833   std::string sqlSpinSelect = "SELECT runnumber, qa_level, badrunqa FROM " + dbtable + " WHERE runnumber = " + std::to_string(runnumber) + " AND qa_level = " + std::to_string(qa_level);
0834 
0835   std::cout << sqlSpinSelect << std::endl;
0836 
0837   odbc::Statement *stmtSpinSelect = DBInterface::instance()->getStatement(dbname);
0838   std::unique_ptr<odbc::ResultSet> rsSpin;
0839   try
0840   {
0841     rsSpin = std::unique_ptr<odbc::ResultSet>(stmtSpinSelect->executeQuery(sqlSpinSelect));
0842   }
0843   catch (odbc::SQLException &e)
0844   {
0845     std::cout << PHWHERE
0846               << " Exception caught at XingShiftCal::SpinDBQA when querying spin DB" << std::endl;
0847     std::cout << "Message: " << e.getMessage() << std::endl;
0848     return 0;
0849   }
0850   if (rsSpin->next())
0851   {
0852     prevbadrunval = rsSpin->getInt("badrunqa");
0853     if (rsSpin->wasNull())
0854     {
0855       std::cout << "SPINDBQA: badrunqa is NULL. Setting to 0 for qa check. " << std::endl;
0856       prevbadrunval = 0;
0857     }
0858     if (true)
0859     {
0860       std::cout << "run " << runnumber << " exists in " << dbtable
0861                 << ", ready to do QA" << std::endl;
0862     }
0863     runExists = true;
0864   }
0865   else
0866   {
0867     if (true)
0868     {
0869       std::cout << "run " << runnumber << " NOT exists in " << dbtable
0870                 << ", no QA" << std::endl;
0871     }
0872   }
0873 
0874   int badrunQA = 0;
0875 
0876   if (prevbadrunval > 0)
0877   {
0878     std::cout << "SPINDBQA: badrunqa is already > 0. No additional qa is performed." << std::endl;
0879     return 0;
0880   }
0881   //  else
0882   //  {
0883   // =========== Do bad run QA here =============
0884   // if (conditions pass && previously existing badRunQA != 1): badrunQA = 0
0885   // if (conditions fail (bad run)): badrunQA = 1
0886 
0887   // if spin pattern does not match known MCR pattern
0888   std::string scdev_blue;
0889   std::string scdev_yell;
0890   for (int crossing = 0; crossing < 120; crossing++)
0891   {
0892     int ibluespin = blueSpinPattern[crossing];
0893     int iyellspin = yellSpinPattern[crossing];
0894     if (ibluespin == 1)
0895     {
0896       scdev_blue.push_back('+');
0897     }
0898     else if (ibluespin == -1)
0899     {
0900       scdev_blue.push_back('-');
0901     }
0902     else
0903     {
0904       scdev_blue.push_back('*');
0905     }
0906 
0907     if (iyellspin == 1)
0908     {
0909       scdev_yell.push_back('+');
0910     }
0911     else if (iyellspin == -1)
0912     {
0913       scdev_yell.push_back('-');
0914     }
0915     else
0916     {
0917       scdev_yell.push_back('*');
0918     }
0919   }
0920   // std::string scdev_blue = TH1_to_string(hspinpatternBlue);
0921   // std::string scdev_yell = TH1_to_string(hspinpatternYellow);
0922   std::string pattern_name = "UNKNOWN";
0923 
0924   for (std::map<std::string, std::string>::const_iterator ii = preset_pattern_blue.begin(); ii != preset_pattern_blue.end(); ++ii)
0925   {
0926     std::string key = (*ii).first;
0927     if (preset_pattern_blue[key] == scdev_blue && preset_pattern_yellow[key] == scdev_yell)
0928     {
0929       pattern_name = key;
0930     }
0931   }
0932 
0933   if (pattern_name == "UNKNOWN")
0934   {
0935     badrunQA = 1;
0936     std::cout << "SPINDBQA: Pattern is unidentified from known CDEV pattern. Setting bad run." << std::endl;
0937   }
0938 
0939   // if pc spin pattern does not match intended spin pattern within < 10 bunches
0940   int mismatches = 0;
0941   //    std::string spin_pattern_blue = "";
0942   //    std::string spin_pattern_yell = "";
0943   for (int crossing = 0; crossing < 120; crossing++)
0944   {
0945     int spin_cdev_blue = blueSpinPattern[crossing];
0946     int spin_cdev_yell = yellSpinPattern[crossing];
0947     int spin_pC_blue = bluePcSpinPattern[crossing];
0948     int spin_pC_yell = yellPcSpinPattern[crossing];
0949 
0950     if (spin_pC_blue == -1 || spin_pC_blue == 1)
0951     {
0952       if (spin_cdev_blue != spin_pC_blue && !(spin_cdev_blue == 0 && spin_pC_blue == 10))
0953       {
0954         mismatches += 1;
0955       }
0956     }
0957 
0958     if (spin_pC_yell == -1 || spin_pC_yell == 1)
0959     {
0960       if (spin_cdev_yell != spin_pC_yell && !(spin_cdev_blue == 0 && spin_pC_blue == 10))
0961       {
0962         mismatches += 1;
0963       }
0964     }
0965   }
0966 
0967   if (mismatches > 10)
0968   {
0969     badrunQA = 1;
0970     std::cout << "SPINDBQA: CDEV pattern has > 10 mismatched bunches from pC polarimeter. Setting bad run." << std::endl;
0971   }
0972 
0973   // if crossing shift != 0
0974   int xing_correction_offset = -999;
0975   if (success)
0976   {
0977     xing_correction_offset = xingshift;
0978   }
0979 
0980   if (xing_correction_offset != 0)
0981   {
0982     badrunQA = 1;
0983     std::cout << "SPINDBQA: Crossing shift does not equal 0. Setting bad run." << std::endl;
0984   }
0985 
0986   // if polarization <= 0 || > 1.00 //makes sure polarization from CNI aren't garbage values
0987   if (polBlue <= 0.0 || polBlue > 100.0)
0988   {
0989     badrunQA = 1;
0990     std::cout << "SPINDBQA: Blue beam polarization is unknown. Setting bad run." << std::endl;
0991   }
0992   if (polYellow <= 0.0 || polYellow > 100.0)
0993   {
0994     badrunQA = 1;
0995     std::cout << "SPINDBQA: Yellow beam polarization is unknown. Setting bad run." << std::endl;
0996   }
0997 
0998   // ============================================
0999 
1000   //================ connect to spin db write ====================
1001   rsSpin.reset();
1002   dbname = "spinDB_write";
1003   dbtable = "spin";
1004   if (runExists)
1005   {
1006     // prepare insert sql
1007     std::string sql = "UPDATE " + dbtable + " SET badrunqa = " + std::to_string(badrunQA) + " WHERE runnumber = " + std::to_string(runnumber) + " AND qa_level = " + std::to_string(qa_level);
1008 
1009     std::cout << sql << std::endl;
1010 
1011     // exec sql
1012     odbc::Statement *stmtSpin = DBInterface::instance()->getStatement(dbname);
1013     try
1014     {
1015       stmtSpin->executeUpdate(sql);
1016     }
1017     catch (odbc::SQLException &e)
1018     {
1019       std::cout << PHWHERE
1020                 << " Exception caught at XingShiftCal::SpinDBQA when insert badrunqa into spin DB" << std::endl;
1021       std::cout << "Message: " << e.getMessage() << std::endl;
1022       commitSuccessSpinDB = 0;
1023       return 0;
1024     }
1025   }
1026 
1027   return 0;
1028 }
1029 
1030 std::string XingShiftCal::SQLArrayConstF(float x, int n)
1031 {
1032   std::ostringstream s;
1033   s << "'{";
1034   for (int i = 0; i < n; i++)
1035   {
1036     s << x;
1037     if (i < n - 1)
1038     {
1039       s << ",";
1040     }
1041   }
1042   s << "}'";
1043   return s.str();
1044 }