29 : base_class( name, svcloc ) {
32 declareProperty(
"UseDatabase", m_dbFlag =
false );
33 declareProperty(
"UseEndcapTuning",
35 declareProperty(
"EffFile", m_effFile = std::string(
"no path" ) );
36 declareProperty(
"ResFile", m_resFile = std::string(
"no path" ) );
37 declareProperty(
"EffFile_endcap", m_effFile_endcap = std::string(
"no path" ) );
38 declareProperty(
"ResFile_endcap", m_resFile_endcap = std::string(
"no path" ) );
39 declareProperty(
"path_mdc", m_path = std::string(
"no path" ) );
40 declareProperty(
"Host", host = std::string(
"bes3db2.ihep.ac.cn" ) );
41 declareProperty(
"DbName", dbName = std::string(
"offlinedb" ) );
42 declareProperty(
"UserName", userName = std::string(
"guest" ) );
43 declareProperty(
"Password", password = std::string(
"guestpass" ) );
44 declareProperty(
"SerialNo", serialNo = 0 );
45 declareProperty(
"fromDB", m_fromDB =
true );
46 declareProperty(
"ParBossVer", m_ParBossVer = std::string(
"unknown" ) );
48 int no[43] = { 40, 44, 48, 56, 64, 72, 80, 80, 76, 76, 88, 88, 100, 100, 112,
49 112, 128, 128, 140, 140, 160, 160, 160, 160, 176, 176, 176, 176, 208, 208,
50 208, 208, 240, 240, 240, 240, 256, 256, 256, 256, 288, 288, 288 };
52 for (
int i = 0; i < 43; i++ ) { cellNo[i] = no[i]; }
194 double lay,
bin, expect, hit;
196 std::istringstream readMCEff;
198 if ( m_fromDB ) { readMCEff.str( eff_con ); }
201 ifstream in( eff_con.c_str() );
207 istreambuf_iterator<char>
iter( in );
208 string strCache = string(
iter, ( istreambuf_iterator<char>() ) );
209 readMCEff.str( strCache );
213 ifstream fin( eff_con.c_str() );
217 cout <<
" ERROR: the mdc tunning eff file " << m_effFile
218 <<
" not exist, please check the input! " << endl;
222 if ( !readMCEff.good() )
224 cout <<
" ERROR: mdc tuning eff file " << m_effFile <<
" not exist. " << endl;
230 if ( fin ) cout <<
" Open mdc tuning eff file: " << m_effFile << endl;
231 for ( i = 0; i < 43; i++ )
234 getline( readMCEff, line );
235 for ( j = 0; j < docaNo; j++ ) { readMCEff >>
bin >> docaEff[i][j] >> expect >> hit; }
237 getline( readMCEff, line );
238 for ( j = 0; j < thetaNo; j++ ) { readMCEff >>
bin >> thetaEff[i][j] >> expect >> hit; }
240 getline( readMCEff, line );
241 for ( j = 0; j < cellNo[i]; j++ ) { readMCEff >>
bin >> cellEff[i][j] >> expect >> hit; }
243 for ( i = 0; i < 43; i++ )
246 getline( readMCEff, line );
247 for ( j = 0; j < docaNo; j++ ) { readMCEff >>
bin >> docaEff_2[i][j] >> expect >> hit; }
249 getline( readMCEff, line );
250 for ( j = 0; j < thetaNo; j++ )
251 { readMCEff >>
bin >> thetaEff_2[i][j] >> expect >> hit; }
253 getline( readMCEff, line );
254 for ( j = 0; j < cellNo[i]; j++ )
255 { readMCEff >>
bin >> cellEff_2[i][j] >> expect >> hit; }
266 ifstream readMCRes( m_resFile.c_str() );
267 if ( !readMCRes.good() )
269 cout <<
" ERROR: mdc tuning file: " << m_resFile <<
" not exist. " << endl;
274 cout <<
" Open mdc tuning file: " << m_resFile << endl;
275 for ( i = 0; i < 43; i++ )
278 getline( readMCRes, line );
279 getline( readMCRes, line );
280 for ( j = 0; j < docaNo; j++ )
282 readMCRes >>
bin >> docaRes[i][j][0][0] >> docaRes[i][j][0][1];
285 getline( readMCRes, line );
286 getline( readMCRes, line );
287 for ( j = 0; j < docaNo; j++ )
289 readMCRes >>
bin >> docaRes[i][j][1][0] >> docaRes[i][j][1][1];
310 std::istringstream readMCRes;
311 if ( m_fromDB ) { readMCRes.str( res_con ); }
314 ifstream in( res_con.c_str() );
315 istreambuf_iterator<char>
iter( in );
316 string strCache = string(
iter, ( istreambuf_iterator<char>() ) );
317 readMCRes.str( strCache );
319 if ( !readMCRes.good() )
321 cout <<
" ERROR: mdc tuning file: " << m_resFile <<
" not exist. " << endl;
326 cout <<
" MdcTunningSvc::setMcRes2() Open mdc tuning resfile " << m_resFile << endl;
327 for ( i = 0; i < 43; i++ )
330 getline( readMCRes, line );
331 getline( readMCRes, line );
332 for ( j = 0; j < docaNo; j++ )
334 readMCRes >>
bin >> docaF[i][j][0] >> docaMean1[i][j][0] >> docaSigma1[i][j][0] >>
335 docaMean2[i][j][0] >> docaSigma2[i][j][0];
338 getline( readMCRes, line );
339 getline( readMCRes, line );
340 for ( j = 0; j < docaNo; j++ )
342 readMCRes >>
bin >> docaF[i][j][1] >> docaMean1[i][j][1] >> docaSigma1[i][j][1] >>
343 docaMean2[i][j][1] >> docaSigma2[i][j][1];
346 for ( i = 0; i < 43; i++ )
349 getline( readMCRes, line );
350 getline( readMCRes, line );
351 for ( j = 0; j < docaNo; j++ )
353 readMCRes >>
bin >> docaF_2[i][j][0] >> docaMean1_2[i][j][0] >>
354 docaSigma1_2[i][j][0] >> docaMean2_2[i][j][0] >>
355 docaSigma2_2[i][j][0];
358 getline( readMCRes, line );
359 getline( readMCRes, line );
360 for ( j = 0; j < docaNo; j++ )
362 readMCRes >>
bin >> docaF_2[i][j][1] >> docaMean1_2[i][j][1] >>
363 docaSigma1_2[i][j][1] >> docaMean2_2[i][j][1] >>
364 docaSigma2_2[i][j][1];
377 std::istringstream readMCRes;
378 if ( m_fromDB ) { readMCRes.str( res_con ); }
381 ifstream in( res_con.c_str() );
382 istreambuf_iterator<char>
iter( in );
383 string strCache = string(
iter, ( istreambuf_iterator<char>() ) );
384 readMCRes.str( strCache );
387 ifstream fin( res_con.c_str() );
392 cout <<
" ERROR: the mdc tunning res file " << m_resFile
393 <<
" not exist, please check the input!" << endl;
396 if ( !readMCRes.good() )
398 cout <<
" ERROR: the mdc tuning res file: " << m_resFile
399 <<
" not exist, please check the input! " << endl;
406 cout <<
" MdcTunningSvc::setMcRes3() Open mdc tuning resfile: " << m_resFile << endl;
407 for ( i = 0; i < 43; i++ )
410 getline( readMCRes, line );
411 getline( readMCRes, line );
412 for ( j = 0; j < docaNo; j++ )
414 readMCRes >>
bin >> docaF[i][j][0] >> docaMean1[i][j][0] >> docaSigma1[i][j][0] >>
415 docaMean2[i][j][0] >> docaSigma2[i][j][0] >> resLargest[i][j][0] >>
416 resSmallest[i][j][0] >> resRatio[i][j][0];
419 getline( readMCRes, line );
420 getline( readMCRes, line );
421 for ( j = 0; j < docaNo; j++ )
423 readMCRes >>
bin >> docaF[i][j][1] >> docaMean1[i][j][1] >> docaSigma1[i][j][1] >>
424 docaMean2[i][j][1] >> docaSigma2[i][j][1] >> resLargest[i][j][1] >>
425 resSmallest[i][j][1] >> resRatio[i][j][1];
428 for ( i = 0; i < 43; i++ )
431 getline( readMCRes, line );
432 getline( readMCRes, line );
433 for ( j = 0; j < docaNo; j++ )
435 readMCRes >>
bin >> docaF_2[i][j][0] >> docaMean1_2[i][j][0] >>
436 docaSigma1_2[i][j][0] >> docaMean2_2[i][j][0] >> docaSigma2_2[i][j][0] >>
437 resLargest_2[i][j][0] >> resSmallest_2[i][j][0] >>
441 getline( readMCRes, line );
442 getline( readMCRes, line );
443 for ( j = 0; j < docaNo; j++ )
446 readMCRes >>
bin >> docaF_2[i][j][1] >> docaMean1_2[i][j][1] >>
447 docaSigma1_2[i][j][1] >> docaMean2_2[i][j][1] >> docaSigma2_2[i][j][1] >>
448 resLargest_2[i][j][1] >> resSmallest_2[i][j][1] >>
492 for (
int jj = 0; jj < 9; jj++ )
494 if ( ( driftD < mindD ) || ( driftD > maxdD ) ) { bindD = maxbin; }
495 else if ( ( driftD >= jj ) && ( driftD < ( jj + 1 ) ) ) { bindD = jj; }
497 double y0D = ( m_BesMdcRes->getD_dD( layerId, bindD ) );
498 double y1D = ( m_BesMdcRes->getD_dD( layerId, bindD + 1 ) );
499 double yD = y0D + ( y1D - y0D ) * ( driftD - bindD );
500 double y0M = ( m_BesMdcRes->getM_dD( layerId, bindD ) );
501 double y1M = ( m_BesMdcRes->getM_dD( layerId, bindD + 1 ) );
502 double yM = y0M + ( y1M - y0M ) * ( driftD - bindD );
503 double dely = yD - yM;
521 double minCos = -0.8;
522 double minCos2 = -0.7;
525 for (
int ii = 0; ii < 16; ii++ )
527 if ( ( costta < minCos ) || ( costta > maxCos ) ) { binTa = maxTa; }
528 else if ( ( costta >= ( minCos + ii * 0.1 ) ) && ( costta < ( minCos2 + ii * 0.1 ) ) )
532 double y0D = ( m_BesMdcRes->getD_theta( layerId, binTa ) );
533 double y1D = ( m_BesMdcRes->getD_theta( layerId, binTa + 1 ) );
534 double y0M = ( m_BesMdcRes->getM_theta( layerId, binTa ) );
535 double y1M = ( m_BesMdcRes->getM_theta( layerId, binTa + 1 ) );
537 double yD[16], yM[16], Del[16];
538 for (
int ll = 0; ll < 16; ll++ )
540 yD[ll] = y0D + ( y1D - y0D ) / 0.1 * ( costta - ( minCos + ll * 0.1 ) );
541 yM[ll] = y0M + ( y1M - y0D ) / 0.1 * ( costta - ( minCos + ll * 0.1 ) );
542 Del[ll] = yD[ll] - yM[ll];
547 if ( ( binTa >= 0 ) && ( binTa <= 5 ) ) { delTha = Del[binTa] * 0.118; }
548 else if ( ( binTa > 5 ) && ( binTa <= 10 ) ) { delTha = Del[binTa] * 0.518; }
549 else if ( ( binTa > 10 ) && ( binTa <= 15 ) ) { delTha = Del[binTa] * 0.218; }
556 driftD = fabs( driftD );
562 if ( posFlag == 0 ) driftD *= -1;
564 if ( layerId < 0 || layerId > 42 )
565 std::cout <<
" MdcTuningSvc:wrong LayerId " << layerId << std::endl;
566 if ( cellId < 0 || cellId >= cellNo[layerId] )
567 std::cout <<
"MdcTuningSvc:wrong cellId " << cellId << std::endl;
569 if ( fabs( cosTheta ) > 1 )
571 std::cout <<
"MdcTuningSvc:wrong coseTheta " << cosTheta << std::endl;
575 int thetaBin = (int)floor( ( cosTheta + 1 ) * thetaNo / 2. );
579 int docaBin = (int)floor( ( driftD + 12 ) * docaNo / 24. );
580 if ( m_EndcapTuning == 0 )
581 eff = docaEff[layerId][docaBin] * thetaEff[layerId][thetaBin] * cellEff[layerId][cellId];
584 if ( fabs( cosTheta ) <= 0.83 )
585 eff = docaEff[layerId][docaBin] * thetaEff[layerId][thetaBin] * cellEff[layerId][cellId];
587 eff = docaEff_2[layerId][docaBin] * thetaEff_2[layerId][thetaBin] *
588 cellEff_2[layerId][cellId];
599 int posFlag,
double entranceAngle,
double& mean,
602 driftD = fabs( driftD );
608 if ( posFlag == 0 ) driftD *= -1;
610 if ( layerId < 0 || layerId > 42 )
611 std::cout <<
" MdcTuningSvc:wrong LayerId " << layerId << std::endl;
612 if ( cellId < 0 || cellId >= cellNo[layerId] )
613 std::cout <<
"MdcTuningSvc:wrong cellId " << cellId << std::endl;
615 if ( fabs( cosTheta ) > 1 )
617 std::cout <<
"MdcTuningSvc:wrong cosTheta " << cosTheta << std::endl;
625 int docaBin = (int)floor( ( driftD + 12 ) * docaNo / 24. );
626 if ( entranceAngle < 0 )
628 mean = docaRes[layerId][docaBin][0][0];
629 sigma = docaRes[layerId][docaBin][0][1];
633 mean = docaRes[layerId][docaBin][1][0];
634 sigma = docaRes[layerId][docaBin][1][1];
646 int posFlag,
double entranceAngle,
double&
f,
double& mean1,
647 double& sigma1,
double& mean2,
double& sigma2 ) {
649 driftD = fabs( driftD );
655 if ( posFlag == 0 ) driftD *= -1;
657 if ( layerId < 0 || layerId > 42 )
658 std::cout <<
" MdcTuningSvc:wrong LayerId " << layerId << std::endl;
659 if ( cellId < 0 || cellId >= cellNo[layerId] )
660 std::cout <<
"MdcTuningSvc:wrong cellId " << cellId << std::endl;
662 if ( fabs( cosTheta ) > 1 )
664 std::cout <<
"MdcTuningSvc:wrong cosTheta " << cosTheta << std::endl;
672 int docaBin = (int)floor( ( driftD + 12 ) * docaNo / 24. );
673 if ( m_EndcapTuning == 0 )
675 if ( entranceAngle < 0 )
677 f = docaF[layerId][docaBin][0];
678 mean1 = docaMean1[layerId][docaBin][0];
679 sigma1 = docaSigma1[layerId][docaBin][0];
680 mean2 = docaMean2[layerId][docaBin][0];
681 sigma2 = docaSigma2[layerId][docaBin][0];
685 f = docaF[layerId][docaBin][1];
686 mean1 = docaMean1[layerId][docaBin][1];
687 sigma1 = docaSigma1[layerId][docaBin][1];
688 mean2 = docaMean2[layerId][docaBin][1];
689 sigma2 = docaSigma2[layerId][docaBin][1];
694 if ( fabs( cosTheta ) <= 0.83 )
696 if ( entranceAngle < 0 )
698 f = docaF[layerId][docaBin][0];
699 mean1 = docaMean1[layerId][docaBin][0];
700 sigma1 = docaSigma1[layerId][docaBin][0];
701 mean2 = docaMean2[layerId][docaBin][0];
702 sigma2 = docaSigma2[layerId][docaBin][0];
706 f = docaF[layerId][docaBin][1];
707 mean1 = docaMean1[layerId][docaBin][1];
708 sigma1 = docaSigma1[layerId][docaBin][1];
709 mean2 = docaMean2[layerId][docaBin][1];
710 sigma2 = docaSigma2[layerId][docaBin][1];
715 if ( entranceAngle < 0 )
717 f = docaF_2[layerId][docaBin][0];
718 mean1 = docaMean1_2[layerId][docaBin][0];
719 sigma1 = docaSigma1_2[layerId][docaBin][0];
720 mean2 = docaMean2_2[layerId][docaBin][0];
721 sigma2 = docaSigma2_2[layerId][docaBin][0];
725 f = docaF_2[layerId][docaBin][1];
726 mean1 = docaMean1_2[layerId][docaBin][1];
727 sigma1 = docaSigma1_2[layerId][docaBin][1];
728 mean2 = docaMean2_2[layerId][docaBin][1];
729 sigma2 = docaSigma2_2[layerId][docaBin][1];
745 int posFlag,
double entranceAngle,
double&
f,
double& mean1,
746 double& sigma1,
double& mean2,
double& sigma2,
747 double& ResLargest,
double& ResSmallest,
double& ResRatio ) {
749 driftD = fabs( driftD );
755 if ( posFlag == 0 ) driftD *= -1;
757 if ( layerId < 0 || layerId > 42 )
758 std::cout <<
" MdcTuningSvc:wrong LayerId " << layerId << std::endl;
759 if ( cellId < 0 || cellId >= cellNo[layerId] )
760 std::cout <<
"MdcTuningSvc:wrong cellId " << cellId << std::endl;
762 if ( fabs( cosTheta ) > 1 )
764 std::cout <<
"MdcTuningSvc:wrong cosTheta " << cosTheta << std::endl;
772 int docaBin = (int)floor( ( driftD + 12 ) * docaNo / 24. );
773 if ( m_EndcapTuning == 0 )
775 if ( entranceAngle < 0 )
777 f = docaF[layerId][docaBin][0];
778 mean1 = docaMean1[layerId][docaBin][0];
779 sigma1 = docaSigma1[layerId][docaBin][0];
780 mean2 = docaMean2[layerId][docaBin][0];
781 sigma2 = docaSigma2[layerId][docaBin][0];
782 ResLargest = resLargest[layerId][docaBin][0];
783 ResSmallest = resSmallest[layerId][docaBin][0];
784 ResRatio = resRatio[layerId][docaBin][0];
788 f = docaF[layerId][docaBin][1];
789 mean1 = docaMean1[layerId][docaBin][1];
790 sigma1 = docaSigma1[layerId][docaBin][1];
791 mean2 = docaMean2[layerId][docaBin][1];
792 sigma2 = docaSigma2[layerId][docaBin][1];
793 ResLargest = resLargest[layerId][docaBin][1];
794 ResSmallest = resSmallest[layerId][docaBin][1];
795 ResRatio = resRatio[layerId][docaBin][1];
800 if ( fabs( cosTheta ) <= 0.83 )
802 if ( entranceAngle < 0 )
804 f = docaF[layerId][docaBin][0];
805 mean1 = docaMean1[layerId][docaBin][0];
806 sigma1 = docaSigma1[layerId][docaBin][0];
807 mean2 = docaMean2[layerId][docaBin][0];
808 sigma2 = docaSigma2[layerId][docaBin][0];
809 ResLargest = resLargest[layerId][docaBin][0];
810 ResSmallest = resSmallest[layerId][docaBin][0];
811 ResRatio = resRatio[layerId][docaBin][0];
815 f = docaF[layerId][docaBin][1];
816 mean1 = docaMean1[layerId][docaBin][1];
817 sigma1 = docaSigma1[layerId][docaBin][1];
818 mean2 = docaMean2[layerId][docaBin][1];
819 sigma2 = docaSigma2[layerId][docaBin][1];
820 ResLargest = resLargest[layerId][docaBin][1];
821 ResSmallest = resSmallest[layerId][docaBin][1];
822 ResRatio = resRatio[layerId][docaBin][1];
827 if ( entranceAngle < 0 )
829 f = docaF_2[layerId][docaBin][0];
830 mean1 = docaMean1_2[layerId][docaBin][0];
831 sigma1 = docaSigma1_2[layerId][docaBin][0];
832 mean2 = docaMean2_2[layerId][docaBin][0];
833 sigma2 = docaSigma2_2[layerId][docaBin][0];
834 ResLargest = resLargest_2[layerId][docaBin][0];
835 ResSmallest = resSmallest_2[layerId][docaBin][0];
836 ResRatio = resRatio_2[layerId][docaBin][0];
840 f = docaF_2[layerId][docaBin][1];
841 mean1 = docaMean1_2[layerId][docaBin][1];
842 sigma1 = docaSigma1_2[layerId][docaBin][1];
843 mean2 = docaMean2_2[layerId][docaBin][1];
844 sigma2 = docaSigma2_2[layerId][docaBin][1];
845 ResLargest = resLargest_2[layerId][docaBin][1];
846 ResSmallest = resSmallest_2[layerId][docaBin][1];
847 ResRatio = resRatio_2[layerId][docaBin][1];
907 if ( enterA < 0 ) { iEntr = 0; }
910 if ( ilr == 0 ) { driftD = -1. * driftD; }
911 else { driftD = driftD; }
913 if ( ( driftD < mindD ) || ( driftD > maxdD ) ) { bindD = maxbin; }
916 for (
double dd = -9.; dd < 9.; dd++ )
919 if ( ( driftD >= dd ) && ( driftD < ( dd + 1. ) ) )
927 double y0D = ( m_BesMdcRes->getD_iEntr( lay, iEntr, bindD ) );
928 double y1D = ( m_BesMdcRes->getD_iEntr( lay, iEntr, bindD + 1 ) );
929 double yD = y0D + ( y1D - y0D ) * ( driftD - dD[bindD] );
930 double y0M = ( m_BesMdcRes->getM_iEntr( lay, iEntr, bindD ) );
931 double y1M = ( m_BesMdcRes->getM_iEntr( lay, iEntr, bindD + 1 ) );
932 double yM = y0M + ( y1M - y0M ) * ( driftD - dD[bindD] );
933 double dely = yD - yM;
944 MsgStream log(
msgSvc(), name() );
945 SmartDataPtr<Event::EventHeader> eventHeader( m_eventSvc,
"/Event/EventHeader" );
947 int run = eventHeader->runNumber();
949 log << MSG::INFO <<
"MdcTuningSvc::getMdcTuningTableInfo() run =" << run << endmsg;
950 if ( m_ParBossVer == std::string(
"unknown" ) )
951 cout <<
"MdcTuningSvc::getMdcTuningTableInfo() : ERROR: there is no ParBossVer " << endl;
953 log << MSG::INFO <<
"MdcTuningSvc::getMdcTuningTableInfo() : ParBossVer = " << m_ParBossVer
963 for (
int i = 0; i < 1000; i++ )
968 cout <<
" ==================== " << endl;
972 "select MdcRes,MdcEff from MdcTuning where RunFrom <= %d and RunTo >= %d and "
974 run1, run1, m_ParBossVer.c_str() );
975 cout <<
" stmt1: " << stmt1 << endl;
978 int status = m_dbsvc->query(
"offlinedb", stmt1, result );
981 cout <<
" ERROR: can not read MdcRes, MdcEff from the MdcTuning table " << endl;
982 log << MSG::ERROR <<
" ERROR Read MdcRes, MdcEff from the MdcTuning table " << endmsg;
983 return StatusCode::FAILURE;
986 if ( result.size() >= 1 )
1012 "select MdcRes,MdcEff from MdcTuning where RunFrom <= %d and RunTo >= %d and "
1014 run2, run2, m_ParBossVer.c_str() );
1017 status = m_dbsvc->query(
"offlinedb", stmt2, result );
1020 log << MSG::ERROR <<
" ERROR Read MdcRes, MdcEff.dEdxTuning from the MdcTuning table "
1022 return StatusCode::FAILURE;
1025 if ( result.size() >= 1 )
1038 if ( cnt != 0 && cnt != 1000 )
1040 log << MSG::INFO <<
" get MDC tuning data from run " << run + cnt * j <<
" instead of run "
1045 cout <<
" cnt = " << cnt << endl;
1048 log << MSG::ERROR <<
" can not read Data from DB" << endmsg;
1050 return StatusCode::FAILURE;
1062 int row = result.size() - 1;
1063 cout <<
" row = " << row << endl;
1067 cout <<
" ERROR: can not read Data from DB, please check MdcTunningSvc Version. " << endl;
1068 return StatusCode::FAILURE;
1071 string ggg = result[row]->GetString(
"MdcEff" );
1072 string fff = result[row]->GetString(
"MdcRes" );
1074 log << MSG::DEBUG <<
" MdcTunning Data: MdcEff: " << ggg <<
" MdcRes: " << fff << endmsg;
1081 if ( !stEff )
return StatusCode::FAILURE;
1082 if ( !stRes )
return StatusCode::FAILURE;
1083 return StatusCode::SUCCESS;
double GetRes2(int layerId, int cellId, double driftD, double cosTheta, int posFlag, double entranceAngle, double &f, double &mean1, double &sigma1, double &mean2, double &sigma2)
double GetRes3(int layerId, int cellId, double driftD, double cosTheta, int posFlag, double entranceAngle, double &f, double &mean1, double &sigma1, double &mean2, double &sigma2, double &ResLargest, double &ResSmallest, double &ResRatio)