#include <CalClustersAlg.h>
Public Methods | |
CalClustersAlg (const std::string &name, ISvcLocator *pSvcLocator) | |
constructor. More... | |
virtual | ~CalClustersAlg () |
destructor. More... | |
StatusCode | initialize () |
StatusCode | execute () |
StatusCode | finalize () |
double | Leak (double sum, double elast) |
Leakage corrections with last layer. More... | |
void | Profile (double sum, CsICluster *cl) |
Leakage corrections with profile fitting. More... | |
Vector | Fit_Direction (std::vector< Vector > pos, std::vector< Vector > sigma2, int nlayers) |
Direction reconstruction. More... | |
Protected Methods | |
StatusCode | retrieve () |
Private Attributes | |
ICalGeometrySvc * | m_CalGeo |
CalRecLogs * | m_CalRecLogs |
the log list, the input of the reconstruction. More... | |
CsIClusterList * | m_CsIClusterList |
the clusters list, the output of the reconstruction. More... | |
Midnight * | minuit |
the minimizer for Profile(). More... | |
int | m_callNumber |
The reconstruction here uses CalRecLogs to produce a CsIClusterList. It evaluates the barycenter for each layer using the coordinates stored in the CalRecLogs, and tries to correct for energy leakage using two different methods:
For a comparison one can see on the following plots the results of this method on R138 data and a MC run of 20 GeV positrons
Definition at line 56 of file CalClustersAlg.h.
|
constructor.
Definition at line 427 of file CalClustersAlg.cpp. References m_callNumber.
00427 : 00428 //################################################ 00429 Algorithm(name, pSvcLocator) 00430 { 00431 declareProperty("callNumber",m_callNumber=0); 00432 00433 } |
|
destructor.
Definition at line 64 of file CalClustersAlg.h.
00064 {}; |
|
Performs the reconstruction.
Definition at line 513 of file CalClustersAlg.cpp. References CalRecLog::energy(), g_elayer, CalLogID::layer(), logwidth, nbins, CalRecLog::position(), CsICluster::setDirection(), CsICluster::setEneLayer(), CsICluster::setEneLeak(), CsICluster::setPosLayer(), CsICluster::setRmsLayer(), CsICluster::setRmsLong(), CsICluster::setRmsTrans(), CsICluster::setTransvOffset(), slope, and CalLogID::view().
00515 { 00516 MsgStream log(msgSvc(), name()); 00517 StatusCode sc = StatusCode::SUCCESS; 00518 sc = retrieve(); 00519 const Point p0(0.,0.,0.); 00520 00521 int rectkr=0; //is tracker recon OK? 00522 int ngammas; 00523 Point gammaVertex; 00524 Vector gammaDirection; 00525 00526 SmartDataPtr<ISiRecObjs> tkrRecData(eventSvc(),"/Event/TkrRecon/SiRecObjs"); 00527 if (tkrRecData == 0) { 00528 log << MSG::INFO << "No TKR Reconstruction available " << endreq; 00529 // return sc; 00530 } 00531 else 00532 { 00533 // First get reconstructed direction from tracker 00534 ngammas = tkrRecData->numGammas(); 00535 log << MSG::INFO << "number of gammas = " << ngammas << endreq; 00536 00537 00538 if (ngammas > 0) { 00539 rectkr++; 00540 gammaVertex = tkrRecData->getGammaVertex(0); 00541 gammaDirection = tkrRecData->getGammaDirection(0); 00542 slope = fabs(gammaDirection.z()); 00543 log << MSG::DEBUG << "gamma direction = " << slope << endreq; 00544 00545 } else { 00546 log << MSG::INFO << "No reconstructed gammas " << endreq; 00547 } 00548 } 00549 int nLogs = m_CalRecLogs->num(); 00550 double ene = 0; 00551 Vector pCluster(p0); 00552 int nLayers = m_CalGeo->numLayers() * m_CalGeo->numViews(); 00553 00554 std::vector<double> eneLayer(nLayers,0.); 00555 std::vector<Vector> pLayer(nLayers); 00556 std::vector<Vector> rmsLayer(nLayers); 00557 00558 00559 00560 // Compute barycenter and various moments 00561 00562 for (int jlog = 0; jlog < nLogs ; jlog++) { 00563 CalRecLog* recLog = m_CalRecLogs->Log(jlog); 00564 00565 double eneLog = recLog->energy(); 00566 Vector pLog = recLog->position() - p0; 00567 int layer = nLayers-1 - (recLog->layer() * 2 + recLog->view()); 00568 00569 eneLayer[layer]+=eneLog; 00570 00571 Vector ptmp = eneLog*pLog; 00572 pLayer[layer] += ptmp; 00573 00574 Vector ptmp_sqr(ptmp.x()*pLog.x(),ptmp.y()*pLog.y(),ptmp.z()*pLog.z()); 00575 rmsLayer[layer] += ptmp_sqr; // Position error is assumed to be 1/sqrt(eneLog) 00576 00577 ene += eneLog; 00578 pCluster += ptmp; 00579 } 00580 00581 // Now take the means 00582 if(ene>0.)pCluster *= (1./ene); else pCluster=Vector(-1000., -1000., -1000.); 00583 int i = 0; 00584 for( ;i<nLayers;i++){ 00585 if(eneLayer[i]>0) 00586 { 00587 pLayer[i] *= (1./eneLayer[i]); 00588 rmsLayer[i] *= (1./eneLayer[i]); 00589 00590 Vector sqrLayer(pLayer[i].x()*pLayer[i].x(),pLayer[i].y()*pLayer[i].y(),pLayer[i].z()*pLayer[i].z()); 00591 00592 00593 Vector d; 00594 if(i%2 == 1) d = Vector(logwidth*logwidth/12.,0.,0.); 00595 else d = Vector(0.,logwidth*logwidth/12.,0.); 00596 00597 rmsLayer[i] += d-sqrLayer; 00598 00599 } 00600 else 00601 { 00602 pLayer[i]=p0; 00603 rmsLayer[i]=p0; 00604 } 00605 } 00606 00607 00608 // Now sum the different rms to have one transverse and one longitudinal rms 00609 double rms_trans=0; 00610 double rms_long=0; 00611 std::vector<Vector> posrel(nLayers); 00612 00613 00614 for(int ilayer=0;ilayer<nLayers;ilayer++) 00615 { 00616 00617 posrel[ilayer]=pLayer[ilayer]-pCluster; 00618 00619 // Sum alternatively the rms 00620 if(ilayer%2) 00621 { 00622 rms_trans += rmsLayer[ilayer].y(); 00623 rms_long += rmsLayer[ilayer].x(); 00624 } 00625 else 00626 { 00627 rms_trans += rmsLayer[ilayer].x(); 00628 rms_long += rmsLayer[ilayer].y(); 00629 } 00630 } 00631 00632 00633 // Compute direction using the positions and rms per layer 00634 Vector caldir = Fit_Direction(posrel,rmsLayer,nLayers); 00635 00636 00637 // if no tracker rec then fill slope 00638 if(!rectkr) slope = caldir.z(); 00639 00640 //slope=1; // Temporary whilst the algorith appplies to slope=1 showers only. 00641 00642 // Take square roots of RMS 00643 // rms_trans = sqrt(rms_trans); 00644 // rms_long = sqrt(rms_long); 00645 00646 // Fill CsICluster data 00647 CsICluster* cl = new CsICluster(ene,pCluster+p0); 00648 m_CsIClusterList->add(cl); 00649 cl->setEneLayer(eneLayer); 00650 cl->setPosLayer(pLayer); 00651 cl->setRmsLayer(rmsLayer); 00652 cl->setRmsLong(rms_long); 00653 cl->setRmsTrans(rms_trans); 00654 cl->setDirection(caldir); 00655 00656 // Leakage correction 00657 double eleak = Leak(ene,eneLayer[nLayers-1])+ene; 00658 00659 // iteration 00660 eleak = Leak(eleak,eneLayer[nLayers-1])+ene; 00661 00662 00663 cl->setEneLeak(eleak); 00664 00665 // defines global variable to be used for fcn 00666 g_elayer.resize(nLayers); 00667 for ( i =0;i<nLayers;i++) 00668 { 00669 // We are working in GeV 00670 g_elayer[i] = eneLayer[i]/1000.; 00671 } 00672 nbins = nLayers; 00673 // slope = 1; // temporary 00674 00675 // Do profile fitting 00676 Profile(ene,cl); 00677 00678 if(ngammas>0){ 00679 Vector calOffset = (p0+pCluster) - gammaVertex; 00680 double calLongOffset = gammaDirection*calOffset; 00681 double calTransvOffset =sqrt(calOffset.mag2() - calLongOffset*calLongOffset); 00682 cl->setTransvOffset(calTransvOffset); 00683 00684 00685 00686 } 00687 00688 m_CsIClusterList->writeOut(); 00689 00690 return sc; 00691 } |
|
Finalization of algorithm
Definition at line 698 of file CalClustersAlg.cpp.
00700 { 00701 StatusCode sc = StatusCode::SUCCESS; 00702 00703 00704 // delete Minuit object 00705 delete minuit; 00706 00707 00708 // m_CsIClusterList->writeOut(); 00709 00710 return sc; 00711 } |
|
Direction reconstruction. Basic algorithm for now, since we need to have knowledge on longitudinal errors Simply reconstruct direction on both sides XZ and YZ Definition at line 337 of file CalClustersAlg.cpp.
00339 { 00340 00341 MsgStream log(msgSvc(), name()); 00342 00343 // sigma2.z() is useless here no matter its value. 00344 double cov_xz = 0; // covariance x,z 00345 double cov_yz = 0; // covariance y,z 00346 double mx=0; // mean x 00347 double my=0; // mean y 00348 double mz1=0; // mean z for x pos 00349 double mz2=0; // mean z for y pos 00350 double norm1=0; 00351 double norm2=0; 00352 double var_z1=0; // variance of z 00353 double var_z2=0; 00354 int nlx=0,nly=0; 00355 Vector nodir(-1000.,-1000.,-1000.); 00356 for(int il=0;il<nlayers;il++) 00357 { 00358 00359 00360 // For the moment forget about longitudinal position 00361 if(il%2==1) 00362 { 00363 if (sigma2[il].x()>0.) 00364 { 00365 nlx++; 00366 double err = 1/sigma2[il].x(); 00367 cov_xz += pos[il].x()*pos[il].z()*err; 00368 var_z1 += pos[il].z()*pos[il].z()*err; 00369 mx += pos[il].x()*err; 00370 mz1 += pos[il].z()*err; 00371 norm1 += err; 00372 } 00373 } 00374 else 00375 { 00376 if(sigma2[il].y()>0.) 00377 { 00378 00379 nly++; 00380 double err = 1/sigma2[il].y(); 00381 cov_yz += pos[il].y()*pos[il].z()*err; 00382 var_z2 += pos[il].z()*pos[il].z()*err; 00383 my += pos[il].y()*err; 00384 mz2 += pos[il].z()*err; 00385 norm2 += err; 00386 } 00387 } 00388 } 00389 00390 00391 if(nlx <2 || nly < 2 )return nodir; 00392 00393 00394 00395 00396 mx /= norm1; 00397 mz1 /= norm1; 00398 cov_xz /= norm1; 00399 cov_xz -= mx*mx; 00400 var_z1 /= norm1; 00401 var_z1 -= mz1*mz1; 00402 if(var_z1 == 0) return nodir; 00403 double tgthx = cov_xz/var_z1; 00404 00405 00406 my /= norm2; 00407 mz2 /= norm2; 00408 cov_yz /= norm2; 00409 cov_yz -= my*my; 00410 var_z2 /= norm2; 00411 var_z2 -= mz2*mz2; 00412 00413 // Now we have cov(x,z) and var(z) we can deduce slope 00414 if(var_z2 == 0) return nodir; 00415 double tgthy = cov_yz/var_z2; 00416 00417 00418 double tgtheta_sqr = tgthx*tgthx+tgthy*tgthy; 00419 double costheta = 1/sqrt(1+tgtheta_sqr); 00420 // log << MSG::INFO << norm2 << "\t" << norm1 << "\t" << var_z2 << "\t" << var_z1 << endreq; 00421 Vector dir(costheta*tgthx,costheta*tgthy,costheta); 00422 return dir; 00423 } |
|
Definition at line 436 of file CalClustersAlg.cpp. References g_elayer, logheight, and logwidth.
00438 { 00439 MsgStream log(msgSvc(), name()); 00440 StatusCode sc = StatusCode::SUCCESS; 00441 sc = service("CalGeometrySvc", m_CalGeo); 00442 00443 if(sc.isFailure()) 00444 { 00445 log << MSG::ERROR << "CalGeometrySvc could not be found" <<endreq; 00446 return sc; 00447 } 00448 00449 setProperties(); 00450 log << MSG::INFO << "callNumber = " << m_callNumber << endreq; 00451 00452 logheight = m_CalGeo->logHeight(); 00453 logwidth = m_CalGeo->logWidth(); 00454 00455 00456 // Minuit object 00457 minuit = new Midnight(5); 00458 00459 //Sets the function to be minimized 00460 minuit->SetFCN(fcn); 00461 00462 00463 g_elayer.clear(); 00464 00465 return sc; 00466 } |
|
Leakage corrections with last layer. The second method uses the correlation between the escaping energy and the energy deposited in the last layer of the calorimeter. Indeed, the last layer carries the most important information concerning the leaking energy: the total number of particles escaping through the back should be nearly proportional to the energy deposited in the last layer. The measured signal in that layer can therefore be modified to account for the leaking energy. We used the Monte Carlo simulation of the GLAST beam test configuration to deter mine this correlation at several energies, from 2 GeV up to 40 GeV. For one par ticular incident energy, the bidimensionnal distribution of the energy escaping and the energy deposited in the last layer can be fitted by a simple linear function: The and parameters are proportional to the logarithm of the incident energy and to its square, respectively. Because the only information we have, initially, on the incident energy is the total measured energy , we have to use it as the estimator of . The reconstructed energy is then: To improve the result, one can iterate using the new estimator to determine the correct values of and .
Definition at line 134 of file CalClustersAlg.cpp. References slope.
00136 { 00137 if(eTotal<200.) return 0.; 00138 else 00139 { 00140 // Evaluation of energy using correlation method 00141 // Coefficients fitted using GlastSim. 00142 double p0 = -1.49 + 1.72*slope; 00143 double p1 = 0.28 + 0.434 * slope; 00144 double p2 = -15.16 + 11.55 * slope; 00145 double p3 = 13.88 - 10.18 * slope; 00146 double lnE = log(eTotal/1000.); 00147 double funcoef = (p0 + p1 * lnE )/(1+exp(-p2*(lnE - p3))); 00148 00149 double e_leak = funcoef * elast; 00150 00151 // Evaluation of energy using correlation woth last layer 00152 // coefficients fitted using tbsim and valid for ~1GeV<E<~50GeV 00153 //double slope = 1.111 + 0.557*log(eTotal/1000.); 00154 //double intercept = 210. + 112. * log(eTotal/1000.) *log(eTotal/1000.); 00155 //double e_leak = slope * elast + intercept; 00156 return e_leak; 00157 } 00158 } |
|
Leakage corrections with profile fitting. It performs a longitudinal profile fitting using the incomplete gamma function ( gamma.cxx). The mean energy density per length unit is taken as: Thus integrated on the i th Xtal pathlength it gives the 2 shower parameters here alpha and lambda describes the maximum position and and the exponential decrease of the profile. Those parameters have been estimated using a MC and their dependance over E has been fitted by a power law. They are log-normally distributed with a very broad distribution ( hence some of the shower fluctuations ). Therefore they should not be included in the fitting process. Here we use 4 parameters: total energy starting point alpha lambda They can be fixed or released in Profile() The input is:
Definition at line 198 of file CalClustersAlg.cpp. References slope.
00200 { 00201 00202 if( eTotal<2000. || slope == 0) //algorithm is useless under several GeV 00203 00204 { 00205 cl->setFitEnergy(0); // Conversion to MeV 00206 cl->setProfChisq(0); 00207 cl->setCsiStart(0); 00208 cl->setCsiAlpha(0); 00209 cl->setCsiLambda(0); 00210 } 00211 else 00212 { 00213 double fit_energy; 00214 double ki2; 00215 double fit_alpha; 00216 double fit_lambda; 00217 double fit_start; 00218 double energy_err; 00219 double alpha_err; 00220 double lambda_err; 00221 double start_err; 00222 00223 // Vector of step, initial min and max value 00224 float vstrt[5]; 00225 float stp[5]; 00226 float bmin[5]; 00227 float bmax[5]; 00228 00229 // We are working in GeV 00230 double eTotal_GeV = eTotal / 1000; 00231 00232 // par[0] is energy 00233 // par[1] is alpha 00234 // par[2] is the starting point 00235 // par[3] is lambda 00236 00237 // Init start values and bounds 00238 00239 // starting value of each parameter 00240 vstrt[0] = eTotal_GeV; 00241 vstrt[1] = 2.65 * exp(0.15*log(eTotal_GeV)); // parametrisation of alpha 00242 vstrt[2] = 1.8f; // eq to 1X0 in CsI 00243 vstrt[3] = 2.29 * exp(-0.031*log(eTotal_GeV)); 00244 // step value of each parameter 00245 stp[0] = 0.1f; 00246 stp[1] = 0.1f; 00247 stp[2] = 0.02f; 00248 stp[3] = 0.2f; 00249 00250 // minimum value of each parameter 00251 bmin[0] = 0.5*eTotal_GeV; 00252 bmin[1] = 0.5; 00253 bmin[2] = -5; 00254 bmin[3] = 0.; 00255 00256 // maximum value of each parameter 00257 bmax[0] = 5 * eTotal_GeV; 00258 bmax[1] = 15; 00259 bmax[2] = 10; 00260 bmax[3] = 10; 00261 00262 // Those are the arguments for Minuit 00263 double arglist[10]; 00264 int ierflg = 0; 00265 00266 // Set no output because of tuple output 00267 arglist[0] = -1; 00268 minuit->mnexcm("SET PRI", arglist ,1,ierflg); 00269 00270 // idem with warnings ( minuit prints warnings when the Hessian matrix is not positive ) 00271 minuit->mnexcm("SET NOW", arglist ,1,ierflg); 00272 00273 arglist[0] = 1; 00274 minuit->mnexcm("SET ERR", arglist ,1,ierflg); 00275 00276 // defines the strategy used by minuit 00277 // 1 is standard 00278 arglist[0] = 2; 00279 minuit->mnexcm("SET STR", arglist ,1,ierflg); 00280 00281 00282 // Defines parameters 00283 00284 minuit->mnparm(0, "Energy", vstrt[0], stp[0], bmin[0],bmax[0],ierflg); 00285 minuit->mnparm(1, "Alpha", vstrt[1], stp[1], bmin[1],bmax[1],ierflg); 00286 minuit->mnparm(2, "Starting point", vstrt[2], stp[2], bmin[2],bmax[2],ierflg); 00287 minuit->mnparm(3, "Lambda", vstrt[3], stp[3], bmin[3],bmax[3],ierflg); 00288 00289 // Fix some parameters 00290 // alpha 00291 arglist[0] = 2; 00292 minuit->mnexcm("FIX ", arglist ,1,ierflg); 00293 00294 // lambda 00295 arglist[0] = 4; 00296 minuit->mnexcm("FIX ", arglist ,1,ierflg); 00297 00298 00299 // Calls Migrad with 500 iterations maximum 00300 arglist[0]=500; 00301 arglist[1]=1; 00302 minuit->mnexcm("MIGRAD",arglist,2,ierflg); 00303 00304 // Retrieve parameter information 00305 00306 minuit->GetParameter( 0, fit_energy,energy_err ); 00307 minuit->GetParameter( 1, fit_alpha,alpha_err ); 00308 minuit->GetParameter( 2, fit_start,start_err ); 00309 minuit->GetParameter( 3, fit_lambda,lambda_err ); 00310 00311 // Get chi-square 00312 double edm,errdef; 00313 int nvpar,nparx,icstat; 00314 minuit->mnstat(ki2,edm,errdef,nvpar,nparx,icstat); 00315 00316 // Fills data 00317 cl->setFitEnergy(1000*fit_energy); // Conversion to MeV 00318 cl->setProfChisq(ki2); 00319 cl->setCsiStart(fit_start); 00320 cl->setCsiAlpha(fit_alpha); 00321 cl->setCsiLambda(fit_lambda); 00322 00323 00324 // Clear minuit 00325 arglist[0] = 1; 00326 minuit->mnexcm("CLEAR", arglist ,1,ierflg); 00327 00328 } 00329 00330 } |
|
Definition at line 469 of file CalClustersAlg.cpp.
00471 { 00472 00473 StatusCode sc = StatusCode::SUCCESS; 00474 00475 MsgStream log(msgSvc(), name()); 00476 log << MSG::INFO << "Initialize" << endreq; 00477 00478 DataObject* pnode=0; 00479 00480 sc = eventSvc()->retrieveObject( "/Event/CalRecon", pnode ); 00481 00482 if( sc.isFailure() ) { 00483 sc = eventSvc()->registerObject("/Event/CalRecon",new DataObject); 00484 if( sc.isFailure() ) { 00485 00486 log << MSG::ERROR << "Could not create CalRecon directory" << endreq; 00487 return sc; 00488 } 00489 } 00490 m_CsIClusterList = SmartDataPtr<CsIClusterList> (eventSvc(),"/Event/CalRecon/CsIClusterList"); 00491 // sc = eventSvc()->retrieveObject("/Event/CalRecon/CsIClusterList",m_CsIClusterList); 00492 if (!m_CsIClusterList ){ 00493 m_CsIClusterList = 0; 00494 m_CsIClusterList = new CsIClusterList(); 00495 sc = eventSvc()->registerObject("/Event/CalRecon/CsIClusterList",m_CsIClusterList); 00496 } else { 00497 m_CsIClusterList->clear(); 00498 } 00499 00500 m_CalRecLogs = SmartDataPtr<CalRecLogs>(eventSvc(),"/Event/CalRecon/CalRecLogs"); 00501 00502 00503 // sc = eventSvc()->retrieveObject("/Event/CalRecon/CalADCLogs",m_CalRawLogs); 00504 return sc; 00505 } |
|
Definition at line 84 of file CalClustersAlg.h. |
|
Definition at line 91 of file CalClustersAlg.h. Referenced by CalClustersAlg(). |
|
the log list, the input of the reconstruction.
Definition at line 86 of file CalClustersAlg.h. |
|
the clusters list, the output of the reconstruction.
Definition at line 88 of file CalClustersAlg.h. |
|
the minimizer for Profile().
Definition at line 90 of file CalClustersAlg.h. |