1 /*******************************************************************************
2 * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
4 * Author: The IceCube RALICE-based Offline Project.
5 * Contributors are mentioned in the code where appropriate.
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation strictly for non-commercial purposes is hereby granted
9 * without fee, provided that the above copyright notice appears in all
10 * copies and that both the copyright notice and this permission notice
11 * appear in the supporting documentation.
12 * The authors make no claims about the suitability of this software for
13 * any purpose. It is provided "as is" without express or implied warranty.
14 *******************************************************************************/
18 ///////////////////////////////////////////////////////////////////////////
20 // TTask derived class to perform track fitting via minimisation of a
21 // convoluted Pandel pdf.
23 // The code in this processor is based on the algorithms as developed
24 // by Oladipo Fadiran, George Japaridze (Clark Atlanta University, USA)
25 // and Nick van Eijndhoven (Utrecht University, The Netherlands).
27 // For the minimisation process the TFitter facility, which is basically Minuit,
28 // is used. Minimisation is performed by invokation of the SIMPLEX method,
29 // followed by an invokation of HESSE to determine the uncertainties on the results.
30 // The statistics of the TFitter result are stored as an AliSignal object
31 // in the track, which can be obtained via the GetFitDetails memberfunction.
32 // In the minimisation procedure an overall plausibility for the fitted track
33 // is determined based on a convoluted Pandel pdf value for each used hit.
34 // This track plausibility is expressed in terms of a Bayesian psi value
35 // w.r.t. a Convoluted Pandel PDF.
36 // The Baysian psi value is defined as -loglikelihood in a decibel scale.
37 // This implies psi=-10*log10(L) where L=p(D|HI) being the likelihood of
38 // the data D under the hypothesis H and prior information I.
39 // Since all (associated) hits contribute independently to the Bayesian psi
40 // value, this psi value is built up by summation of the various hit contributions.
41 // As such, the FitDetails entries contain the statistics of all the different
42 // hit contributions, like PsiMedian, PsiMean, and PsiSigma.
43 // The Bayesian psi value is available in the fit details under the name "PsiSum".
44 // In addition the standard Minuit results like IERFIT, FCN, EDM etc... are
45 // also available from the FitDetails.
47 // The convoluted Pandel value is evaluated in various areas in the distance-time
48 // space as described in the CPandel writeup by O. Fadiran, G. Japaridze
49 // and N. van Eijndhoven.
50 // In case the distance-time point of a certain hit falls outside the
51 // validity rectangle, the point is moved onto the corresponding side location
52 // of the rectangle. For this new location the Pandel value is evaluated for
53 // this hit and an extra penalty is added to the corresponding psi value
55 // By default this penalty value amounts to 0 dB, but the user can
56 // modify this penalty value via the memberfunction SetPenalty.
57 // This allows investigation/tuning of the sensitivity to hits with
58 // extreme distance and/or time residual values.
60 // Use the UseTracks memberfunction to specify the first guess tracks
61 // to be processed by the minimiser.
62 // By default only the first encountered IceDwalk track will be processed.
64 // Use the SelectHits memberfunction to specify the hits to be used.
65 // By default only the hits associated to the first guess track are used.
67 // The fit processor printlevel can be selected via the memberfunction SetPrintLevel.
68 // By default all printout is suppressed (i.e. level=-2).
70 // An example of how to invoke this processor after Xtalk, hit cleaning
71 // and a direct walk first guess estimate can be found in the ROOT example
72 // macro icepandel.cc which resides in the /macros subdirectory.
74 // The minimisation results are stored in the IceEvent structure as
75 // tracks with as default the name "IcePandel" (just like the first guess
76 // results of e.g. IceDwalk).
77 // This track name identifier can be modified by the user via the
78 // SetTrackName() memberfunction. This will allow unique identification
79 // of tracks which are produced when re-processing existing data with
80 // different criteria.
81 // By default the charge of the produced tracks is set to 0, since
82 // no distinction can be made between positive or negative tracks.
83 // However, the user can define the track charge by invokation
84 // of the memberfunction SetCharge().
85 // This facility may be used to distinguish tracks produced by the
86 // various reconstruction algorithms in a (3D) colour display
87 // (see the class AliHelix for further details).
88 // A pointer to the first guess track which was used as input is available
89 // via the GetParentTrack facility of these "IcePandel" tracks.
90 // Furthermore, all the hits that were used in the minisation are available
91 // via the GetSignal facility of a certain track.
93 // An example of how the various data can be accessed is given below,
94 // where "evt" indicates the pointer to the IceEvent structure.
96 // Example for accessing data :
97 // ----------------------------
98 // TObjArray* tracks=evt->GetTracks("IcePandel");
99 // if (!tracks) return;
100 // AliPosition* r0=0;
102 // for (Int_t jtk=0; jtk<tracks->GetEntries(); jtk++)
104 // AliTrack* tx=(AliTrack*)tracks->At(jtk);
105 // if (!tx) continue;
107 // r0=tx->GetReferencePoint();
108 // if (r0) r0->Data();
109 // sx=(AliSignal*)tx->GetFitDetails();
110 // if (sx) fcn=sx->GetSignal("FCN");
111 // AliTrack* tx2=tx->GetParentTrack();
112 // if (!tx2) continue;
114 // r0=tx2->GetReferencePoint();
115 // if (r0) r0->Data();
120 // 1) This processor only works properly on data which are Time and ADC
121 // calibrated and contain tracks from first guess algorithms like
123 // 2) In view of the usage of TFitter/Minuit minimisation, a global pointer
124 // to the instance of this class (gIcePandel) and a global static
125 // wrapper function (IcePandelFCN) have been introduced, to allow the
126 // actual minimisation to be performed via the memberfunction FitFCN.
127 // This implies that in a certain processing job only 1 instance of
128 // this IcePandel class may occur.
130 //--- Author: Nick van Eijndhoven 09-feb-2006 Utrecht University
131 //- Modified: NvE $Date$ Utrecht University
132 ///////////////////////////////////////////////////////////////////////////
134 #include "IcePandel.h"
135 #include "Riostream.h"
137 // Global pointer to the instance of this object
138 IcePandel* gIcePandel=0;
140 // TFitter/Minuit interface to IcePandel::FitFCN
141 void IcePandelFCN(Int_t& npar,Double_t* gin,Double_t& f,Double_t* u,Int_t flag)
143 if (gIcePandel) gIcePandel->FitFCN(npar,gin,f,u,flag);
146 ClassImp(IcePandel) // Class implementation to enable ROOT I/O
148 IcePandel::IcePandel(const char* name,const char* title) : TTask(name,title)
150 // Default constructor.
159 fTrackname="IcePandel";
165 // Set the global pointer to this instance
168 ///////////////////////////////////////////////////////////////////////////
169 IcePandel::~IcePandel()
171 // Default destructor.
203 ///////////////////////////////////////////////////////////////////////////
204 void IcePandel::Exec(Option_t* opt)
206 // Implementation of the hit fitting procedure.
209 AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
213 fEvt=(IceEvent*)parent->GetObject("IceEvent");
216 if (!fUseNames) UseTracks("IceDwalk",1);
218 Int_t nclasses=fUseNames->GetEntries(); // Number of first guess classes to be processed
219 Int_t ntkmax=0; // Max. number of tracks for a certain class
225 cout << " *IcePandel* First guess selections to be processed (-1=all)." << endl;
226 for (Int_t i=0; i<nclasses; i++)
228 strx=(TObjString*)fUseNames->At(i);
230 str=strx->GetString();
231 ntkmax=fUseNtk->At(i);
232 cout << " Maximally " << ntkmax << " track(s) per event for procedure : " << str.Data() << endl;
234 cout << " *IcePandel* Hit selection mode : " << fSelhits << endl;
235 cout << " *IcePandel* Penalty value for minimiser : " << fPenalty << " dB." << endl;
238 fPsistats.SetStoreMode(1);
243 const Double_t pi=acos(-1.);
244 const Double_t e=exp(1.);
246 // Initialisation of the minimisation processor
247 Double_t arglist[100];
248 if (!fFitter) fFitter=new TFitter();
250 // The number of reconstructed tracks already present in the event
251 Int_t ntkreco=fEvt->GetNtracks(1);
255 fHits=new TObjArray();
262 // If selected, use all the good quality hits of the complete event
265 TObjArray* hits=fEvt->GetHits("IceGOM");
266 for (Int_t ih=0; ih<hits->GetEntries(); ih++)
268 AliSignal* sx=(AliSignal*)hits->At(ih);
270 if (sx->GetDeadValue("ADC") || sx->GetDeadValue("LE") || sx->GetDeadValue("TOT")) continue;
275 // Track by track processing of the selected first guess classes
282 fTkfit=new AliTrack();
283 fTkfit->SetNameTitle(fTrackname.Data(),"IcePandel fit result");
287 fFitstats=new AliSignal();
288 fFitstats->SetNameTitle("Fitstats","TFitter stats for Pandel fit");
289 fFitstats->SetSlotName("IERFIT",1);
290 fFitstats->SetSlotName("FCN",2);
291 fFitstats->SetSlotName("EDM",3);
292 fFitstats->SetSlotName("NVARS",4);
293 fFitstats->SetSlotName("IERERR",5);
294 fFitstats->SetSlotName("PsiSum",6);
295 fFitstats->SetSlotName("PsiMedian",7);
296 fFitstats->SetSlotName("PsiMean",8);
297 fFitstats->SetSlotName("PsiSigma",9);
299 Float_t x,y,z,theta,phi,t0;
300 Double_t amin,edm,errdef; // Minimisation stats
301 Int_t ierfit,iererr,nvpar,nparx; // Minimisation stats
305 for (Int_t iclass=0; iclass<nclasses; iclass++) // Loop over first guess classes
307 strx=(TObjString*)fUseNames->At(iclass);
309 str=strx->GetString();
310 ntkmax=fUseNtk->At(iclass);
311 TObjArray* tracks=fEvt->GetTracks(str);
312 ntk=tracks->GetEntries();
313 if (ntkmax>0 && ntk>ntkmax) ntk=ntkmax;
315 for (Int_t jtk=0; jtk<ntk; jtk++) // Loop over tracks of a certain class
317 track=(AliTrack*)tracks->At(jtk);
318 if (!track) continue;
320 AliPosition* r0=track->GetReferencePoint();
323 AliTimestamp* tt0=r0->GetTimestamp();
325 // If selected, use only the first guess track associated hits
329 nsig=track->GetNsignals();
330 for (Int_t is=1; is<=nsig; is++)
332 AliSignal* sx=track->GetSignal(is);
334 if (!sx->GetDevice()->InheritsFrom("IceGOM")) continue;
335 if (sx->GetDeadValue("ADC") || sx->GetDeadValue("LE") || sx->GetDeadValue("TOT")) continue;
340 if (!fHits->GetEntries()) continue;
342 r0->GetVector(vec,"car");
343 r0->GetErrors(err,"car");
349 p=track->Get3Momentum();
350 p.GetVector(vec,"sph");
355 t0=fEvt->GetDifference(tt0,"ns");
357 // Process this first guess track with its associated hits
360 // Set user selected TFitter printout level
362 if (fPrint==-2) arglist[0]=-1;
363 fFitter->ExecuteCommand("SET PRINT",arglist,1);
364 if (fPrint==-2) fFitter->ExecuteCommand("SET NOWARNINGS",arglist,0);
366 fFitter->SetFitMethod("loglikelihood");
368 // Define errors to represent 1 sigma for this likelihood scale
369 arglist[0]=5.*log10(e);
370 fFitter->ExecuteCommand("SET ERRORDEF",arglist,1);
372 fFitter->SetParameter(0,"r0x",x,0.1,0,0);
373 fFitter->SetParameter(1,"r0y",y,0.1,0,0);
374 fFitter->SetParameter(2,"r0z",z,0.1,0,0);
375 fFitter->SetParameter(3,"theta",theta,0.001,0,pi);
376 fFitter->SetParameter(4,"phi",phi,0.001,0,2.*pi);
377 fFitter->SetParameter(5,"t0",t0,1.,0,32000);
379 fFitter->SetFCN(IcePandelFCN);
384 ierfit=fFitter->ExecuteCommand("SIMPLEX",arglist,0);
386 fFitter->GetStats(amin,edm,errdef,nvpar,nparx);
389 fFitstats->SetSignal(ierfit,1);
390 fFitstats->SetSignal(amin,2);
391 fFitstats->SetSignal(edm,3);
392 fFitstats->SetSignal(nvpar,4);
394 fFitstats->SetSignal(fPsistats.GetSum(1),6);
395 fFitstats->SetSignal(fPsistats.GetMedian(1),7);
396 fFitstats->SetSignal(fPsistats.GetMean(1),8);
397 fFitstats->SetSignal(fPsistats.GetSigma(1),9);
399 iererr=fFitter->ExecuteCommand("HESSE",arglist,0);
400 fFitstats->SetSignal(iererr,5);
402 // Resulting parameters after minimisation and error calculation
403 vec[0]=fFitter->GetParameter(0);
404 vec[1]=fFitter->GetParameter(1);
405 vec[2]=fFitter->GetParameter(2);
406 err[0]=fFitter->GetParError(0);
407 err[1]=fFitter->GetParError(1);
408 err[2]=fFitter->GetParError(2);
409 pos.SetPosition(vec,"car");
410 pos.SetPositionErrors(err,"car");
413 vec[1]=fFitter->GetParameter(3);
414 vec[2]=fFitter->GetParameter(4);
416 err[1]=fFitter->GetParError(3);
417 err[2]=fFitter->GetParError(4);
418 p.SetVector(vec,"sph");
419 p.SetErrors(err,"sph");
421 t0=fFitter->GetParameter(5);
422 AliTimestamp t0fit((AliTimestamp)(*fEvt));
425 // Enter the fit result as a track in the event structure
427 fTkfit->SetId(ntkreco);
428 fTkfit->SetCharge(fCharge);
429 fTkfit->SetParentTrack(track);
430 pos.SetTimestamp(t0fit);
431 fTkfit->SetTimestamp(t0fit);
432 fTkfit->SetReferencePoint(pos);
433 fTkfit->Set3Momentum(p);
434 for (Int_t ihit=0; ihit<fHits->GetEntries(); ihit++)
436 AliSignal* sx=(AliSignal*)fHits->At(ihit);
437 if (sx) fTkfit->AddSignal(*sx);
439 fTkfit->SetFitDetails(fFitstats);
440 fEvt->AddTrack(fTkfit);
441 } // End loop over tracks
442 } // End loop over first guess classes
445 ///////////////////////////////////////////////////////////////////////////
446 void IcePandel::SetPrintLevel(Int_t level)
448 // Set the fitter (Minuit) print level.
449 // See the TFitter and TMinuit docs for details.
451 // Note : level=-2 suppresses also all fit processor warnings.
453 // The default in the constructor is level=-2.
457 ///////////////////////////////////////////////////////////////////////////
458 void IcePandel::UseTracks(TString classname,Int_t n)
460 // Specification of the first guess tracks to be used.
462 // classname : Specifies the first guess algorithm (e.g. "IceDwalk");
463 // n : Specifies the max. number of these tracks to be used
465 // Note : n<0 will use all the existing tracks of the specified classname
467 // The default is n=-1.
469 // Consecutive invokations of this memberfunction with different classnames
470 // will result in an incremental effect.
474 // UseTracks("IceDwalk",5);
475 // UseTracks("IceLinefit",2);
476 // UseTracks("IceJams");
478 // This will use the first 5 IceDwalk, the first 2 IceLinefit and all the
479 // IceJams tracks which are encountered in the event structure.
483 fUseNames=new TObjArray();
484 fUseNames->SetOwner();
487 if (!fUseNtk) fUseNtk=new TArrayI();
489 // Check if this classname has already been specified before
491 Int_t nen=fUseNames->GetEntries();
492 for (Int_t i=0; i<nen; i++)
494 TObjString* sx=(TObjString*)fUseNames->At(i);
497 if (s==classname) return;
500 // New classname to be added into the storage
501 if (nen >= fUseNames->GetSize()) fUseNames->Expand(nen+1);
502 if (nen >= fUseNtk->GetSize()) fUseNtk->Set(nen+1);
504 TObjString* name=new TObjString();
505 name->SetString(classname);
506 fUseNames->Add(name);
507 fUseNtk->AddAt(n,nen);
509 ///////////////////////////////////////////////////////////////////////////
510 void IcePandel::SelectHits(Int_t mode)
512 // Specification of the hits to be used in the minimisation.
514 // mode = 0 : All hit cleaning survived hits of the complete event are used
515 // 1 : Only the associated hits are used for each first guess track
517 // The default is mode=1.
519 if (mode==0 || mode==1) fSelhits=mode;
521 ///////////////////////////////////////////////////////////////////////////
522 void IcePandel::SetTrackName(TString s)
524 // Set (alternative) name identifier for the produced tracks.
525 // This allows unique identification of (newly) produced pandel tracks
526 // in case of re-processing of existing data with different criteria.
527 // By default the produced tracks have the name "IcePandel" which is
528 // set in the constructor of this class.
531 ///////////////////////////////////////////////////////////////////////////
532 void IcePandel::SetCharge(Float_t charge)
534 // Set user defined charge for the produced tracks.
535 // This allows identification of these tracks on color displays.
536 // By default the produced tracks have charge=0 which is set in the
537 // constructor of this class.
540 ///////////////////////////////////////////////////////////////////////////
541 void IcePandel::SetPenalty(Float_t val)
543 // Set user defined psi penalty value (in dB) in the minimiser for
544 // distance-time points that fall outside the validity rectangle.
545 // This allows investigation/tuning of the sensitivity to hits with
546 // extreme distance and/or time residual values.
547 // By default the penalty val=0 is set in the constructor of this class.
550 ///////////////////////////////////////////////////////////////////////////
551 void IcePandel::FitFCN(Int_t&,Double_t*,Double_t& f,Double_t* x,Int_t)
553 // Minimisation of the Bayesian psi value for a track w.r.t. a Convoluted Pandel PDF.
554 // The Baysian psi value is defined as -loglikelihood in a decibel scale.
555 // This implies psi=-10*log10(L) where L=p(D|HI) being the likelihood of
556 // the data D under the hypothesis H and prior information I.
558 const Float_t c=0.299792; // Light speed in vacuum in meters per ns
559 const Float_t nice=1.35634; // Refractive index of ice
560 const Float_t thetac=acos(1./nice); // Cherenkov angle (in radians)
561 const Float_t lambda=33.3; // Light scattering length in ice
562 const Float_t labs=98; // Light absorbtion length in ice
563 const Float_t cice=c/nice; // Light speed in ice in meters per ns
564 const Float_t tau=557;
565 const Double_t rho=((1./tau)+(cice/labs));
566 const Double_t pi=acos(-1.);
568 // Assumed PMT timing jitter in ns
569 const Double_t sigma=10;
573 // The new r0 and p vectors and t0 from the minimisation
580 r0.SetPosition(vec,"car");
586 p.SetVector(vec,"sph");
590 // Construct a track with the new values from the minimisation
591 fTkfit->SetReferencePoint(r0);
592 fTkfit->Set3Momentum(p);
594 Int_t nhits=fHits->GetEntries();
598 Float_t d,dist,thit,tgeo;
599 Double_t tres,ksi,eta,pandel;
600 Double_t cpandel1,cpandel2,cpandel3,cpandel;
601 Double_t z,k,alpha,beta,phi,n1,n2,n3,u; // Function parameters for regions 3 and 4
605 for (Int_t i=1; i<=nhits; i++)
607 AliSignal* sx=(AliSignal*)fHits->At(i);
609 IceGOM* omx=(IceGOM*)sx->GetDevice();
611 rhit=omx->GetPosition();
612 d=fTkfit->GetDistance(rhit);
615 dist=p.Dot(r12)+d*tan(thetac);
617 thit=sx->GetSignal("LE",7);
620 // The Convoluted Pandel function evaluation
621 // For definitions of functions and validity regions, see the
622 // CPandel writeup of O. Fadiran, G. Japaridze and N. van Eijndhoven
624 // Move points which are outside the validity rectangle in the (tres,ksi) space
625 // to the edge of the validity rectangle and signal the use of the penalty
643 eta=(rho*sigma)-(tres/sigma);
645 if (ksi<=0) // The zero distance (ksi=0) axis
647 cpandel=exp(-tres*tres/(2.*sigma*sigma))/(sigma*sqrt(2.*pi));
649 else if (ksi<=5 && tres>=-5.*sigma && tres<=30.*sigma) // The exact expression in region 1
651 cpandel1=pow(rho,ksi)*pow(sigma,ksi-1.)*exp(-tres*tres/(2.*sigma*sigma))/pow(2.,0.5*(1.+ksi));
652 cpandel2=ROOT::Math::conf_hyperg(ksi/2.,0.5,eta*eta/2.)/TMath::Gamma((ksi+1.)/2.);
653 cpandel3=sqrt(2.)*eta*ROOT::Math::conf_hyperg((ksi+1.)/2.,1.5,eta*eta/2.)/TMath::Gamma(ksi/2.);
655 cpandel=cpandel1*(cpandel2-cpandel3);
657 else if (ksi<=1 && tres>30.*sigma && tres<=3500) // Approximation in region 2
659 pandel=pow(rho,ksi)*pow(tres,(ksi-1.))*exp(-rho*tres)/TMath::Gamma(ksi);
661 cpandel=exp(rho*rho*sigma*sigma/2.)*pandel;
663 else if (ksi<=1 && tres<-5.*sigma && tres>=-25.*sigma) // Approximation in region 5
665 cpandel=pow(rho*sigma,ksi)*pow(eta,-ksi)*exp(-tres*tres/(2.*sigma*sigma))/(sigma*sqrt(2.*pi));
667 else if (ksi<=50 && tres>=0 && tres<=3500) // Approximation in region 3
669 z=-eta/sqrt(4.*ksi-2.);
670 k=0.5*(z*sqrt(1.+z*z)+log(z+sqrt(1.+z*z)));
671 alpha=-tres*tres/(2.*sigma*sigma)+eta*eta/4.-ksi/2.+0.25+k*(2.*ksi-1.);
672 alpha+=-log(1.+z*z)/4.-ksi*log(2.)/2.+(ksi-1.)*log(2.*ksi-1.)/2.+ksi*log(rho)+(ksi-1.)*log(sigma);
673 beta=0.5*(z/sqrt(1.+z*z)-1.);
674 n1=beta*(20.*beta*beta+30.*beta+9.)/12.;
675 n2=pow(beta,2.)*(6160.*pow(beta,4.)+18480.*pow(beta,3.)+19404.*pow(beta,2.)+8028.*beta+945.)/288.;
676 n3=27227200.*pow(beta,6.)+122522400.*pow(beta,5.)+220540320.*pow(beta,4.);
677 n3+=200166120.*pow(beta,3.)+94064328.*pow(beta,2.)+20546550.*beta+1403325.;
678 n3*=pow(beta,3.)/51840.;
679 phi=1.-n1/(2.*ksi-1.)+n2/pow(2.*ksi-1.,2.)-n3/pow(2.*ksi-1.,3.);
680 cpandel=exp(alpha)*phi/TMath::Gamma(ksi);
682 else if (ksi<=50 && tres<0 && tres>=-25.*sigma) // Approximation in region 4
684 z=eta/sqrt(4.*ksi-2.);
685 k=0.5*(z*sqrt(1.+z*z)+log(z+sqrt(1.+z*z)));
686 u=exp(ksi/2.-0.25)*pow(2.*ksi-1.,-ksi/2.)*pow(2.,(ksi-1.)/2.);
687 beta=0.5*(z/sqrt(1.+z*z)-1.);
688 n1=beta*(20.*beta*beta+30.*beta+9.)/12.;
689 n2=pow(beta,2.)*(6160.*pow(beta,4.)+18480.*pow(beta,3.)+19404.*pow(beta,2.)+8028.*beta+945.)/288.;
690 n3=27227200.*pow(beta,6.)+122522400.*pow(beta,5.)+220540320.*pow(beta,4.);
691 n3+=200166120.*pow(beta,3.)+94064328.*pow(beta,2.)+20546550.*beta+1403325.;
692 n3*=pow(beta,3.)/51840.;
693 phi=1.+n1/(2.*ksi-1.)+n2/pow(2.*ksi-1.,2.)+n3/pow(2.*ksi-1.,3.);
694 cpandel=pow(rho,ksi)*pow(sigma,ksi-1.)*exp(-pow(tres,2.)/(2.*pow(sigma,2.))+pow(eta,2.)/4.)/sqrt(2.*pi);
695 cpandel*=u*phi*exp(-k*(2.*ksi-1.))*pow(1.+z*z,-0.25);
697 else // (tres,ksi) outside validity rectangle
700 cout << " *IcePandel::FitFCN* Outside rectangle. We should never get here." << endl;
703 // Use 10*log10 expression to obtain intuitive dB scale
704 // Omit (small) negative values which are possible due to computer accuracy
706 if (cpandel>0) psihit=-10.*log10(cpandel);
708 // Penalty in dB for (tres,ksi) points outside the validity rectangle
709 if (ier) psihit+=fPenalty;
711 // Update the psi statistics for this hit
712 fPsistats.Enter(float(psihit));
716 ///////////////////////////////////////////////////////////////////////////