BRAT 2.4.5
Class index
Full class index
brahmlib
BRAHMS
ROOT page
//____________________________________________________________________
// 
// RICH pid module - makes particle identification from RICH data.
//
// Find the Bfs track table and the RichRdo object in the inNode.
// Calculate the track lines reflection on the RICH mirror and find
// the intersection with the image plane - this should be the center 
// of a ring generated by the particle.
//
// Find a ring by looking at the number of hits in delta radius areas
// around the center.
//

//____________________________________________________________________
//
// $Id: BrRichPidModule.cxx,v 1.15 2002/06/10 13:30:57 ekman Exp $
// $Author: ekman $
// $Date: 2002/06/10 13:30:57 $
// $Copyright: (C) 2001 BRAHMS Collaboration <brahmlib@rhic.bnl.gov>
//
#ifndef BRAT_BrRichPidModule
#include "BrRichPidModule.h"
#endif
#ifndef BRAT_BrGeometryDbManager
#include "BrGeometryDbManager.h"
#endif
#ifndef BRAT_BrParameterDbManager
#include "BrParameterDbManager.h"
#endif
#ifndef BRAT_BrChkvRdo
#include "BrChkvRdo.h"
#endif
#ifndef BRAT_BrRichPid
#include "BrRichPid.h"
#endif
#ifndef BRAT_BrSpectrometerTracks
#include "BrSpectrometerTracks.h"
#endif
#ifndef ROOT_TDirectory
#include "TDirectory.h"
#endif
#ifndef ROOT_TF1
#include "TF1.h"
#endif
#ifndef ROOT_TProfile
#include "TProfile.h"
#endif
#ifndef ROOT_TVector3
#include "TVector3.h"
#endif
#ifndef WIN32
#include <iostream>
#else
#include <iostream.h>
#endif
#ifndef __IOMANIP__
#include <iomanip>
#endif

//____________________________________________________________________
ClassImp(BrRichPidModule);

//____________________________________________________________________
 BrRichPidModule::BrRichPidModule()
{
  // Default constructor. DO NOT USE
  SetState(kSetup);
}
//____________________________________________________________________
 BrRichPidModule::BrRichPidModule(const Char_t* name, const Char_t* title)
: BrModule(name, title)
{
  // Named Constructor
  SetState(kSetup);
  
  SetDRWindow();
  SetMinHitsInRing();
  SetCheckGeometry();
  SetMaxRadius();
  SetRefractiveIndex();
  SetUseD3Momentum();
  SetUseD4Momentum();
  SetImagePlaneOffset();

  fNSnapshots = 0;
  fRichVolume = 0;
  fT5Volume   = 0;
  fRichParams = 0;
  fNDEDR      = 0;
}

//____________________________________________________________________
 void BrRichPidModule::DefineHistograms()
{
  // Define histograms. 

  if (GetState() != kInit) {
    Stop("DefineHistograms", "Must be called after Init"); 
    return;  
  }

  TDirectory* saveDir = gDirectory; 
  fHistDir = gDirectory->mkdir(GetName()); 
  fHistDir->cd();

  // definition of functions
  Char_t* formula_e = Form("%f*tan(acos((1/(%f))*sqrt(1+(%f/(x*x)))))",
			   fMirrorFocalLength,fRefractiveIndex,0.0005*0.0005);  
  Char_t* formula_mu = Form("%f*tan(acos((1/(%f))*sqrt(1+(%f/(x*x)))))",
			   fMirrorFocalLength,fRefractiveIndex,0.105*0.105);
  Char_t* formula_pi = Form("%f*tan(acos((1/(%f))*sqrt(1+(%f/(x*x)))))",
			    fMirrorFocalLength,fRefractiveIndex,0.139*0.139);  
  Char_t* formula_k  = Form("%f*tan(acos((1/(%f))*sqrt(1+(%f/(x*x)))))",
			    fMirrorFocalLength,fRefractiveIndex,0.494*0.494);
  Char_t* formula_p  = Form("%f*tan(acos((1/(%f))*sqrt(1+(%f/(x*x)))))",
			    fMirrorFocalLength,fRefractiveIndex,0.938*0.938);

  fElectronRvsP = new TF1("theoretical_e",formula_e,-30,30);
  fElectronRvsP->SetNpx(100000);
  fMuonRvsP     = new TF1("theoretical_mu",formula_mu,-30,30);
  fPionRvsP     = new TF1("theoretical_pi",formula_pi,-30,30);
  fKaonRvsP     = new TF1("theoratical_k",formula_k,-30,30);
  fProtonRvsP   = new TF1("theoretical_p",formula_p,-30,30);

  fHistDir->Add(fElectronRvsP);
  fHistDir->Add(fMuonRvsP);
  fHistDir->Add(fPionRvsP);
  fHistDir->Add(fKaonRvsP);
  fHistDir->Add(fProtonRvsP);

  // definitions of histograms
  fRingCenters = new TH2F("ringCenters",
			  "Calculated center of rings on the image plane",  
			  100,-13.666,13.666,100,-11.266,11.266);
  fDRVsPhi     = new TH2F("dRVsPhi", "(rTube - rAverage) versus phi", 50,-3.2,3.2,100,-3,3);
  fDRVsPhiAcc  = new TH2F("dRVsPhiAcc", "(rTube - rAverage) versus phi (accepted)", 50,-3.2,3.2,100,-3,3);
  fRing        = new TH2F("ring","average ring",200,-2,2,200,-2,2);
  fRingAcc     = new TH2F("ringAcc","average ring accepted hits",200,-2,2,200,-2,2);
  fMass        = new TH1F("mass","mass spectrum", 750, -1.5, 1.5);
  fRadVsP      = new TH2F("radiusVsMomentum","Radius versus momentum",250,-25,25,100,-1,15);
  fRadVsP1     = new TH2F("radiusVsMomentum_nTracks=1","Radius versus momentum, nTracks=1",650,-25,25,320,-1,15);
  fRadVsP2     = new TH2F("radiusVsMomentum_nTracks>1","Radius versus momentum, nTracks>1",650,-25,25,320,-1,15);
  fHitsInRing  = new TH1F("hitsInRing","Number of hits per ring", 50,0.5,50.5);
  fHitsVsRadius= new TH2F("hitsVsRadius","Number of ring hits vs r",
			  100,-1,15,50,0.5,50.5 );
  fHitsVsPhotons = new TH2F("hitsVsPhotons", "Hits versus number of photons",
			    51,-0.5,50.5,101,-0.5,100.5);
  fHitsVsEstPhotons = new TH2F("hitsVsEstPhotons",
			       "Hits versus estimated number of photons",
			       51,-0.5,50.5,51,-0.5,50.5);
  fMassVsP   = new TH2F("massVsMomentum","massVsMomentum",500,-25,25,750,-1.5,1.5);
  fMassVsRad = new TH2F("massVsRadius","massVsRadius",320,-1,15,750,-1.5,1.5);

  fSnapshots = new TList();
  fHistDir->mkdir("Snapshots");
  fHistDir->cd("Snapshots");

  for (Int_t i = 0; i <= fMaxNSnapshots; i++)
    fSnapshots->Add(new TH2F(Form("Snapshot%d", i),
			     Form("Snapshot of image plane, no.%d", i),
			     22,-13.666,13.666,18,-11.266,11.266));
  
  fHistDir->cd();
  
  fDEDR =  new TList();
  fHistDir->mkdir("DEDR");
  
  // setting titles etc.
  fMass->SetLineWidth(3);
  fMass->SetXTitle("mass [GeV/c^{2}]");

  fRadVsP->SetMarkerSize(0.3);
  fRadVsP->SetMarkerStyle(20);
  fRadVsP->SetXTitle("reconstructed track momentum [GeV/c]");
  fRadVsP->SetYTitle("RICH ring radius [cm]");
  fRadVsP1->SetMarkerSize(0.3);
  fRadVsP1->SetMarkerStyle(20);
  fRadVsP1->SetXTitle("reconstructed track momentum [GeV/c]");
  fRadVsP1->SetYTitle("RICH ring radius [cm]");
  fRadVsP2->SetMarkerSize(0.3);
  fRadVsP2->SetMarkerStyle(20);
  fRadVsP2->SetXTitle("reconstructed track momentum [GeV/c]");
  fRadVsP2->SetYTitle("RICH ring radius [cm]");
  fHitsVsRadius->SetXTitle("radius [cm]");
  fHitsVsRadius->SetYTitle("hits in ring");
  fHitsVsEstPhotons->SetXTitle("estimated number of photons");
  fHitsVsEstPhotons->SetYTitle("hits in ring");
  fHitsVsPhotons->SetXTitle("summed energy signal (photons)");
  fHitsVsPhotons->SetYTitle("hits in ring");

  gDirectory = saveDir;
}

//____________________________________________________________________
 void BrRichPidModule::Init()
{
  // In this method the following is initialized:
  //
  // 1) Geometry and Parameter db managers
  // 2) Rich parameters (tube numbering and positions)
  // 3) The Geometry of the RICH and T5
  // 4) Rich mirror information (focal length, mirror sphere radius...)  
  // 5) Image plane

  // Job-level initialisation
  SetState(kInit);

  fGausFit = new TF1("Fit", "gaus", 0, 15); 

  BrGeometryDbManager  *geoDb = BrGeometryDbManager::Instance();
  BrParameterDbManager *parDb = BrParameterDbManager::Instance();
  
  if (!geoDb) {
    Failure("Init ", "Couldn't instantiate geometry manager");
    return;
  }
  
  if (!parDb) {
    Failure("Init ", "Couldn't instantiate  detector parameter manager");
    return;
  }
  
  fRichParams = 
    (BrChkvParameters*)parDb->GetDetectorParameters("BrChkvParameters", "RICH");
  fRichVolume = 
    (BrDetectorVolume*)geoDb->GetDetectorVolume("BrDetectorVolume","RICH");
  fT5Volume = 
    (BrDetectorVolume*)geoDb->GetDetectorVolume("BrDetectorVolume","T5");

  //------------------------------------------------------------------
  // Initialization of mirror geometry
  
  fMirrorFocalAngle = 9. / (180/TMath::Pi());  // in radians
  fMirrorSphereRadius = 300; // in cm
  fMirrorFocalLength  = 0.5 * fMirrorSphereRadius; // in cm

  Float_t  zOff = 5; // fixed offset
  Double_t x = 0;
  Double_t y = fMirrorSphereRadius * TMath::Sin(fMirrorFocalAngle);
  Double_t z = ( fRichVolume->GetSize()[2]/2 - zOff - 
		  fMirrorSphereRadius * TMath::Cos(fMirrorFocalAngle) );

  fMirrorSphereCenter.SetX(x);
  fMirrorSphereCenter.SetY(y);
  fMirrorSphereCenter.SetZ(z);

  // Definition of image plane
  //
  // the image plane is situated ~150 cm from the center of the
  // mirror, in an angle of 2 * the focal angle (seen from the
  // z-axis).
  TVector3 mirrorCenter(0,0,(fMirrorFocalLength * 2 * 
			     TMath::Cos(fMirrorFocalAngle) + 
			     fMirrorSphereCenter.Z()));
  
  TVector3 focalLineR(0, 0, -1);
  focalLineR.Rotate(2*fMirrorFocalAngle, TVector3(1,0,0));
  BrVector3D focalLine(focalLineR.X(),focalLineR.Y(),focalLineR.Z());

  Float_t halfRadius = fMirrorSphereRadius/2;
  // offsets are in local coordinates
  Float_t offsety = fImagePlaneOffset.Y(); 
  fImagePlaneOffset.SetY(offsety * TMath::Sin((TMath::Pi()/2) - 2* fMirrorFocalAngle));
  fImagePlaneOffset.SetZ(offsety * TMath::Cos((TMath::Pi()/2) - 2* fMirrorFocalAngle));
  fImagePlaneCenter = BrVector3D(mirrorCenter.X() + halfRadius*focalLine.X() + fImagePlaneOffset.X(), 
				 mirrorCenter.Y() + halfRadius*focalLine.Y() + fImagePlaneOffset.Y(), 
				 mirrorCenter.Z() + halfRadius*focalLine.Z() + fImagePlaneOffset.Z()); 
  
  // I need one point and a normal vector to define the plane
  fImagePlane = BrPlane3D(fImagePlaneCenter,focalLine);

  if (DebugLevel()>15) {
    cout << "BrRichPidModule::Init: Image plane middle: "   
	 << fImagePlaneCenter.X() << " "
	 << fImagePlaneCenter.Y() << " "
	 << fImagePlaneCenter.Z() << endl;
  }
}

//____________________________________________________________________
 void BrRichPidModule::Begin()
{
  // Run-level initialisation
  SetState(kBegin);
}

//____________________________________________________________________
 void BrRichPidModule::Event(BrEventNode* inNode, BrEventNode* outNode)
{
  // Following is done in the event method:
  //

  // Per event method
  SetState(kEvent);

  // get bfs track table
  BrDataTable* bfsTrackTable = 
    (BrDataTable*) inNode->GetDataTable("BfsTracks");
  if (!bfsTrackTable) {
    bfsTrackTable = (BrDataTable*) outNode->GetDataTable("BfsTracks");
    if (!bfsTrackTable) {
      if (Verbose()>15) 
	Warning("Event","Could not find Bfs track table.");
      return;
    }
  }
  // get rhic rdo
  BrChkvRdo* richRdo = (BrChkvRdo*) inNode->GetObject("ChkvRdo RICH");
  if (!richRdo) {
    richRdo = (BrChkvRdo*) outNode->GetObject("ChkvRdo RICH");
    if (!richRdo) {
      if (Verbose()>15) 
	Warning("Event","Could not find ChkvRdo Rich.");
      return;
    }
  }
  
  // create data table with BrRichPid objects
  BrDataTable* richPidTable = new BrDataTable("RichPid","Rich pid object table");
  outNode->AddDataTable(richPidTable);

  //-------------------------------------------------------------------------
  //Now get the track info and the rich hit (tube) info:

  // get the number of tracks 
  fNumberOfTracks = bfsTrackTable->GetEntries();
  if ( (fNumberOfTracks == 0) || (fNumberOfTracks>3) ) return;
  
  //highest momentum first...
  if (fNumberOfTracks>1) {
    
    for (Int_t u = 0; u<fNumberOfTracks; u++) {
      Float_t p = ((BrBfsTrack*)bfsTrackTable->At(u))->GetMomentum();
      Int_t   m = u;

      for (Int_t t = u+1; t<fNumberOfTracks; t++) {
	Float_t p1 = ((BrBfsTrack*)bfsTrackTable->At(t))->GetMomentum();
	if (p1 >= p) {
	  p = p1;
	  m = t;
	}
      }
	
      if (m != u) {
	BrBfsTrack* t = (BrBfsTrack*)bfsTrackTable->At(u);
	bfsTrackTable->AddAt(bfsTrackTable->At(m), u);
	bfsTrackTable->AddAt(t, m);
      }
    }  
  }

  //copy tracks into track array
  TRACKHIT trackHits[fNumberOfTracks];
  for (Int_t t = 0; t<fNumberOfTracks; t++) {
    BrBfsTrack* track = (BrBfsTrack*)bfsTrackTable->At(t);        

    //finding the track projections to the image plane
    BrDetectorTrack* t5Track = track->GetBackDetectorTrack();
    BrLine3D trackLineT5 = t5Track->GetTrackLine();
    BrLine3D trackLineG  = fT5Volume->LocalToGlobal(trackLineT5); 
    BrLine3D trackLineRich = fRichVolume->GlobalToLocal(trackLineG);
    BrLine3D reflectedLine = ReflectTrackLineOnMirror(trackLineRich);
    BrVector3D ringCenter = fImagePlane.GetIntersectionWithLine(reflectedLine);    

    // get it in ring center coordinates
    ringCenter = InImagePlaneCoordinates(ringCenter);

    trackHits[t].x = ringCenter.X();
    trackHits[t].y = ringCenter.Y();
    trackHits[t].nr = t;
    trackHits[t].id = track->GetId();
    trackHits[t].nhits = -1;
    trackHits[t].e = -1;
    trackHits[t].p = track->GetMomentum();
    if ((fUseD3Momentum)&&(!fUseD4Momentum))
      trackHits[t].p = track->GetBfsFrontTrack()->GetMomentum();
    if ((fUseD4Momentum)&&(!fUseD3Momentum))
      trackHits[t].p = track->GetBfsBackTrack()->GetMomentum();
  }

  //copy hits in rdo to hits in array
  fNumberOfHits  = richRdo->GetEntries();
  RICHHIT hits[fNumberOfHits];
  for(Int_t i=0; i<fNumberOfHits; i++) {    
    BrChkvRdo::BrChkvHit* hit = (BrChkvRdo::BrChkvHit*)richRdo->GetHit(i);

    hits[i].x = fRichParams->GetTubePosition(hit->GetTubeNum()).X();    
    hits[i].y = fRichParams->GetTubePosition(hit->GetTubeNum()).Y();    
    hits[i].e = hit->GetEnergy(); 
    hits[i].used = kFALSE;
    hits[i].tracknr = -1;

    hits[i].r = new Float_t[fNumberOfTracks];
    for (Int_t t = 0; t<fNumberOfTracks; t++){      
      Float_t dX = hits[i].x - trackHits[t].x;
      Float_t dY = hits[i].y - trackHits[t].y;
      hits[i].r[t] = TMath::Sqrt(dX*dX + dY*dY);   
    }
  }
  //----------------------------------------------------------------

  // loop over tracks 
  for (Int_t t=0; t<fNumberOfTracks; t++) {

    Float_t radius = FindRing(hits, trackHits[t]);
    Float_t momentum = trackHits[t].p;

    Float_t mass=-1;
    if (radius>1)
      mass = CalculateMass(momentum, radius);
    
    // create Rich Pid
    BrRichPid* richPid = new BrRichPid();
    richPid->SetMass(mass);
    richPid->SetRingRadius(radius);
    richPid->SetRingHits(trackHits[t].nhits);
    // Here the summed energy signal should be added ... 
    richPid->SetTrackId(trackHits[t].id);

    richPidTable->Add(richPid);

    if (HistOn()) {
      Snapshot(hits, trackHits[t]);
      fMass->Fill(mass);
      fRingCenters->Fill(trackHits[t].x,trackHits[t].y);    
      fRadVsP->Fill(momentum, radius);
      fMassVsP->Fill(momentum, mass);
      fMassVsRad->Fill(radius, mass);
      if (fNumberOfTracks == 1)
	fRadVsP1->Fill(momentum, radius);
      else
	fRadVsP2->Fill(momentum, radius);
    }
  }
  
  //delete r array
  for(Int_t i=0; i<fNumberOfHits; i++)  
    if (hits[i].r)
      delete [] hits[i].r;
}

//____________________________________________________________________
 BrLine3D BrRichPidModule::ReflectTrackLineOnMirror(const BrLine3D& trackLine)
{
  // Reflects the track line on the focal mirror. 
  // 
  // 1) find the reflection axis (the axis defined by the center of
  //    the mirror sphere and the track-mirror intersection point).
  //
  // 2) find angle between track line and reflection axis
  //
  // 3) find the rotation axis (perpendicular to trackLine and
  //    reflection axis)
  //
  // 4) rotate trackline with 2*angle around reflection axis
  
  BrVector3D intWithMirror = IntersectionWithMirror(trackLine);
  BrVector3D refAxis = intWithMirror - fMirrorSphereCenter;
  refAxis = refAxis.Unit();  

  BrVector3D trackDir = trackLine.GetDirection();
  trackDir = trackDir.Unit();

  Double_t angle = TMath::ACos(refAxis.Dot(trackDir));
  
  BrVector3D rotAxis = trackDir.Cross(refAxis); 

  // ok, there is no rotate method for BrVector3D, so I translate to
  // TVector3, make the rotation and translate back.
  TVector3 rotAxisR(rotAxis.X(),rotAxis.Y(),rotAxis.Z());
  TVector3 newDirR(trackDir.X(), trackDir.Y(), trackDir.Z());
  newDirR.Rotate(2 * angle, rotAxisR);

  BrVector3D newDir(newDirR.X(),newDirR.Y(),newDirR.Z());
  return BrLine3D(intWithMirror,newDir);
}

//____________________________________________________________________
 BrVector3D BrRichPidModule::IntersectionWithMirror(const BrLine3D& trackLine)
{
  // Calculates the intersection between the trackLine and the focal
  // mirror of the RICH (Djamels calculations).
  //
  // find intersection point with sphere:
  //
  // line equations:     sphere:
  //   x = ax*t + xo      (x - xs)^2 + (y - ys)^2 + (z - zs)^2 = r^2
  //   y = ay*t + yo
  //   z = az*t + zo
  //   
  //   Equation to solve:
  //
  //   (axt + xo - xs)^2 + (ayt + yo - ys)^2 + (azt + zo - zs)^2 - r^2 = 0
  //
  //   t^2(ax^2 + ay^2 + az^2) 
  //        + 2t(ax*(xo - xs) + ay*(yo - ys) + az*(zo - zs)) 
  //              + ((xo - xs)^2 + (yo - ys)^2 + (zo - zs)^2 - r^2) = 0
  //
  //   c1 t^2 + c2 t + c3 = 0;

  // new definitions:
  Double_t Xo = trackLine.GetOrigin().X() - fMirrorSphereCenter.X();  // = (xo - xs)
  Double_t Yo = trackLine.GetOrigin().Y() - fMirrorSphereCenter.Y();  // = (yo - ys)
  Double_t Zo = trackLine.GetOrigin().Z() - fMirrorSphereCenter.Z();  // = (zo - zs)
  
  Double_t ax = trackLine.GetDirection().X();
  Double_t ay = trackLine.GetDirection().Y();
  Double_t az = trackLine.GetDirection().Z();
  
  Double_t radius = fMirrorSphereRadius;
  //                                       ______________
  // solve 2nd deg. equation : t = (-c2 + V c2^2 - 4c1c3 )/2c1
  // (the negative solution is not good)

  Double_t c[3] = {
    ax*ax + ay*ay + az*az,
    2*(ax*Xo + ay*Yo + az*Zo),
    Xo*Xo + Yo*Yo + Zo*Zo - radius*radius
  };
  
  Double_t delta = c[1]*c[1] - 4*c[0]*c[2];
  Double_t t = (-c[1] + TMath::Sqrt(delta))/2/c[0];
  
  // intersection point:
  BrVector3D inters(ax*t + trackLine.GetOrigin().X(), 
		    ay*t + trackLine.GetOrigin().Y(), 
		    az*t + trackLine.GetOrigin().Z());

  if (DebugLevel()>15) {
    cout << "BrRichPidModule::IntersectionWithmirror: " << endl
	 << "Track intersection with mirror: " << endl 
	 << "  x = " << inters.X() << endl
      	 << "  y = " << inters.Y() << endl
      	 << "  z = " << inters.Z() << endl;    
  }

  return inters;
}

//____________________________________________________________________
 BrVector3D BrRichPidModule::InImagePlaneCoordinates(const BrVector3D& hit)
{
  // Hit must be on image plane. Return hit coordinates (x,y,0) on
  // Rich image plane.

  if (fImagePlane.GetMinimumDistanceFromPlane(hit)>0.01) {
    Warning("InImagePlaneCoordinates", 
	    "The hit is not on the imageplane - something is screwy!");
    return BrVector3D(0,0,-1);
  }
  
  Float_t x = fImagePlaneCenter.X() - hit.X();

  Float_t dy = hit.Y() - fImagePlaneCenter.Y();
  Float_t dz = hit.Z() - fImagePlaneCenter.Z();

  Float_t y;

  if (dy>0) 
    y = TMath::Sqrt(dy*dy + dz*dz);
  else 
    y = - TMath::Sqrt(dy*dy + dz*dz);

  return BrVector3D(x,y,0);
}

//____________________________________________________________________
 Float_t BrRichPidModule::GuessRadius(RICHHIT* richHits, Int_t trackNumber)  
{
  // Tries to find the radius of the ring.
  //
  // Seach for hits with distance to the ring center in a dR window and
  // fills the number of hits into a histogram.
  // 
  // Fits this histogram with a gaus to find the approximate maximum
  // (radius) , if the maximum of the histogram is too far from the
  // mean of the fit, simply use the max as radius.

  if (fNumberOfHits<fMinHitsInRing)
    return 0;

  TH1F* histE = new TH1F(Form("DEDR%d",fNDEDR),
			 Form("DEDR, no.%d", fNDEDR), 40,-1,12);
  
  // loop over Rich hits
  for(Int_t i=0; i< fNumberOfHits; i++) {
    
    Float_t r = richHits[i].r[trackNumber];
    if (r<fMaxRadius) {
      for (Int_t b=0; b<histE->GetNbinsX(); b++) {
	if (TMath::Abs(r - histE->GetBinCenter(b)) < fDRWindow/2)
	  histE->Fill(histE->GetBinCenter(b),richHits[i].e);    
      }
    }
  }
  
  // fit around maximum
  Float_t max = histE->GetBinCenter(histE->GetMaximumBin());  

  fGausFit->SetParameter(0, histE->GetMaximum());  
  fGausFit->SetParameter(1, max);  
  fGausFit->SetParLimits(1, max-2,max+2);  

  histE->Fit(fGausFit,"Q0","",max-2,max+2);  

  Float_t radius = fGausFit->GetParameter(1);

  if ((TMath::Abs(radius-max)>2.)||(radius<1)) 
    radius = max;

  if ((radius<0)||(radius>fMaxRadius))
    radius = 0;  

  if (HistOn()) {
    fNDEDR++;  
    if (fNDEDR<200) {
      fHistDir->cd("DEDR");
      fDEDR->Add(histE->Clone());
    }
  }  

  delete histE;

  return radius;
}

//____________________________________________________________________
 Float_t BrRichPidModule::FindRing(RICHHIT* richHits, TRACKHIT track)
{
  // Rind a ring with center at (cX, cY) from hits.
  //
  // 1) Requires nHits >= fMinHitsInRing
  // 2) Guesses a radius
  // 3) Checks that there is a reasonable number of hits in the ring
  // 4) If not, remove hits in ring from the hits array and try again
  // 5) Does this 5 times. If no rings found returns 0.
  // 6) If ring is found, refit the radius.
  
  Bool_t  used[fNumberOfHits];
  for (Int_t i=0; i<fNumberOfHits; i++) 
    used[i]     = richHits[i].used;
  
  if (fNumberOfHits<fMinHitsInRing)
    return 0;  
  
  Float_t   radiusSum   = 0;
  Float_t   radiusGuess = 0;
  Int_t     nRingHits   = 0;
  Float_t   nPhotons    = 0;
  Float_t   estNPhotons = 0;
  Int_t     counter     = 0;
  Bool_t    ringFound   = kFALSE;

  // loop until ring found or counter > 5  
  while((!ringFound)&&(counter++<5)) {
    
    // guess radius, find corresponding hits and the estimated number
    // of photons for a ring of that radius.
    radiusGuess = GuessRadius(richHits, track.nr); 
    
    for (Int_t i=0; i<fNumberOfHits; i++) {
      if ((richHits[i].used == kFALSE)&&(TMath::Abs(richHits[i].r[track.nr] - radiusGuess) < fDRWindow/2)) {
	richHits[i].used = kTRUE; 
	nRingHits++;  
	nPhotons = nPhotons + richHits[i].e;
	radiusSum = radiusSum + richHits[i].r[track.nr];
      }
    }    
    estNPhotons = EstimateNumberOfPhotons(radiusGuess);
    
    // if there is enough hits in ring accept it
    // due to saturation ,the rings cannot be expected to have more 
    // than 8 hits.
    if (nRingHits>8) 
      ringFound = kTRUE;
    else if ((nRingHits>(0.4*estNPhotons)&&(nRingHits>=fMinHitsInRing)))      
      ringFound = kTRUE;
    else {
      nRingHits=0;
      nPhotons =0;
      radiusSum=0;
    }
  }
  
  // if no ring found clear the ringHits array and return 0  
  if (!ringFound) 
    return 0;

  // taking the average radius as radius
  Float_t radius=0;
  if (nRingHits>0)
    radius = radiusSum/(Float_t)nRingHits;

  // 
  Float_t phiRad = 0;
  // loop over hits  
  for (Int_t i=0; i<fNumberOfHits; i++) {
    // restore old used hits
    richHits[i].used = used[i];

    // geo hist
    if (fCheckGeometry && HistOn()) {
      phiRad = TMath::ATan2((richHits[i].y-track.y),(richHits[i].x-track.x));
      
      fDRVsPhi->Fill(phiRad, (richHits[i].r[track.nr] - radiusGuess), richHits[i].e);
      if (radiusGuess!=0)
	fRing->Fill(TMath::Cos(phiRad)*richHits[i].r[track.nr]/radiusGuess,
		    TMath::Sin(phiRad)*richHits[i].r[track.nr]/radiusGuess,
		    richHits[i].e);
    }
    
    // find out what hits were used now and add them to used
    if (TMath::Abs(richHits[i].r[track.nr] - radiusGuess) < fDRWindow/2) {
      richHits[i].used = kTRUE;
      richHits[i].tracknr = track.nr;      

      if (fCheckGeometry && HistOn()) {
	fDRVsPhiAcc->Fill(phiRad, (richHits[i].r[track.nr] - radiusGuess), richHits[i].e);
	if (radiusGuess!=0)
	  fRingAcc->Fill(TMath::Cos(phiRad)*richHits[i].r[track.nr]/radiusGuess,
			 TMath::Sin(phiRad)*richHits[i].r[track.nr]/radiusGuess
			 , richHits[i].e);
      }
    }
  }
  track.nhits = nRingHits;
  track.e     = nPhotons;
  
  if (HistOn()) {
    fHitsInRing->Fill(nRingHits);
    fHitsVsEstPhotons->Fill(estNPhotons,Float_t(nRingHits));
    fHitsVsPhotons->Fill(nPhotons,Float_t(nRingHits));
    fHitsVsRadius->Fill(radius,nRingHits);
  } 
  return radius;
}

//____________________________________________________________________
 Float_t BrRichPidModule::EstimateNumberOfPhotons(Float_t radius)
{
  // The number of detected cherenkov photons is given by
  //
  // N = No * L sin^2(theta)
  //
  // where No is a detector quality parameter, L is the path length
  // and theta is the cherenkov angle 

  Float_t sinTheta = TMath::Sin(TMath::ATan(radius/fMirrorFocalLength));
  Float_t N = 55 * 150 * sinTheta * sinTheta;
  
  return N;
}

//____________________________________________________________________
 Float_t BrRichPidModule::CalculateMass(Float_t p, Float_t radius)
{
  // Calculates the theoretical mass from the momentum and the ring
  // radius. 
  //                      ____________
  // we have :  1/beta = V 1 + (m/p)^2   and   cos(theta) = 1/(n*beta)
  //                   _____________________
  //         => m = p V (n*cos(theta))^2 - 1     
  //

  Double_t theta     = TMath::ATan(radius/fMirrorFocalLength);

  Double_t ncostheta = fRefractiveIndex * TMath::Cos(theta);
  Double_t mass      = TMath::Abs(p) * TMath::Sqrt(TMath::Abs(ncostheta*ncostheta -1));
  
  return mass;
}

//____________________________________________________________________
 void BrRichPidModule::Snapshot(RICHHIT* richHits, TRACKHIT track)
{
  if (fNSnapshots<fMaxNSnapshots) {
    TDirectory* saveDir = gDirectory;
    fHistDir->cd();

    //make the snapshot
    TH2F* hist = 
      (TH2F*)fSnapshots->FindObject(Form("Snapshot%d",fNSnapshots));
    fNSnapshots++;
    
    for(Int_t i=0; i<fNumberOfHits; i++) {
      hist->Fill(richHits[i].x,richHits[i].y,richHits[i].e);
      const Char_t* title = 
        Form("Snapshot%03d (x=%03f,y=%06f,p=%06f)",fNSnapshots,track.x,track.y,track.p);
      hist->SetTitle(title);
    }
    gDirectory=saveDir;
  } 
  else {
    if (Verbose()>15)
      Warning("Snapshot","NSnapshots > MaxNSnapshot. Image not created!");
  }    
}

//____________________________________________________________________
 void BrRichPidModule::End()
{
  // Run-level finalisation
  SetState(kEnd);
}

//____________________________________________________________________
 void BrRichPidModule::Finish()
{
  // Job-level finalisation
  SetState(kFinish);
  if (!HistOn())
    return;
  
  TDirectory* saveDir = gDirectory;
  fHistDir->cd();

  if (fCheckGeometry) {
    TProfile* profile = fDRVsPhiAcc->ProfileX("dRVsPhiAccProfile");

    TF1* fit = new TF1("fit","[0]*cos(x +[1])");
    fit->SetParameter(0,profile->GetMaximum()/2);
    profile->Fit(fit,"Q0","Q0",-3.14,3.14);

    Float_t xoff = fit->GetParameter(0) * TMath::Cos(fit->GetParameter(1));
    Float_t yoff = fit->GetParameter(0) * TMath::Sin(fit->GetParameter(1));

    if (Verbose()>4) {
      cout << "BrRichPidModule summary:" << endl;

      cout << "Rings off by approx " << setprecision(2) << fit->GetParameter(0) 
	   << " cm" << endl
	   << "in direction " << setprecision(2) << fit->GetParameter(1) 
	   << " (rad)." << endl;
      cout << "Try new SetImagePlaneOffset("
	   << setprecision(3) << fImagePlaneOffset.GetX() + xoff << "," 
	   << setprecision(3) << fImagePlaneOffset.GetY() + yoff << ");" << endl; 
    }
  }
  gDirectory=saveDir;
}

//____________________________________________________________________
 void BrRichPidModule::Print(Option_t* option) const
{
  // Print module information
  // See BrModule::Print for options.
  // In addition this module defines the Option:
  // <fill in here>

  TString opt(option);
  opt.ToLower(); 
  
  BrModule::Print(option); 
  if (opt.Contains("d")) 
   cout << endl 
         << "  Original author: Claus O. E. Jorgensen" << endl
         << "  Last Modifications: " << endl 
         << "    $Author: ekman $" << endl  
         << "    $Date: 2002/06/10 13:30:57 $"   << endl 
         << "    $Revision: 1.15 $ " << endl  
         << endl 
         << "-------------------------------------------------" << endl;
}

//____________________________________________________________________
//
// $Log: BrRichPidModule.cxx,v $
// Revision 1.15  2002/06/10 13:30:57  ekman
// Small fix to keep calculated masses < 0. It should be changed to m2 soon!
//
// Revision 1.14  2002/04/03 11:32:20  ekman
// Added dR fit in finish method. When fCheckGeometry=kTRUE new imageplane
// offsets are suggested.
//
// Revision 1.13  2002/03/06 21:11:26  ekman
// Fixed bug in momentum sorting algorithm.
//
// Revision 1.12  2002/02/13 11:52:35  ekman
// Added new geo histograms. Introduced sorting of tracks by momentum & other minor changes.
//
// Revision 1.11  2002/02/06 13:41:08  ekman
// small bug fix
//
// Revision 1.10  2002/02/06 12:10:26  ekman
// Added new geo (ring hist)
//
// Revision 1.9  2002/01/31 15:26:09  ouerdane
// increased binning in histograms ring radius vs momentum and mass
//
// Revision 1.8  2001/11/19 15:03:22  ouerdane
// check in Finish if histograms are booked before any actions on histograms, added TDirectory member in the C1 module
//
// Revision 1.7  2001/11/19 10:22:41  ekman
// Removed Stop in event method (if no bfs track).
//
// Revision 1.6  2001/11/05 07:04:04  ouerdane
// changed BFS for Bfs
//
// Revision 1.5  2001/10/27 04:14:30  ekman
// Major changes. Arrays of tubehits and trackhits introduced. New geocheck histograms added.
//
// Revision 1.2  2001/10/02 01:54:49  ouerdane
// removed named contructor calls to Pid data classes
//
// Revision 1.1  2001/09/24 13:15:03  ekman
// Added BrRichPidModule.
//
//

This page automatically generated by script docBrat by Christian Holm

Copyright ; 2002 BRAHMS Collaboration <brahmlib@rcf.rhic.bnl.gov>
Last Update on by

Validate HTML
Validate CSS