BRAT 2.4.5
Class index
Full class index
brahmlib
BRAHMS
ROOT page
// $Id: BrMagnetVolume.cxx,v 1.21 2002/08/30 17:35:06 videbaek Exp $
// $Author: videbaek $
// $Date: 2002/08/30 17:35:06 $
//


///////////////////////////////////////////////////////////////////////
//
// BrMagnetVolume is a BRAHMS data class providing storage and 
// access function for magnetic volume and fieldinformation. The
// base class deals with an effective edge approximation. The idea is
// to have derived classes handle more complicated field.
//
//
// The magnet filed can now be set using the currents, rather than reading
// field from file. Example
// d5magvol->SetCurrent(350,"B")
//
// The default polynominal coefficients are sets in the constructor.
// The class is derived from BrDetectorVolume which maintains the coordinate system
// description, while this derived class contains the specific information about
// fields description, and current fiels values.
//
//////////////////////////////////////////////////////////////////////


#include <cstdio>
#include <BrIostream.h>

#ifndef ROOT_TString
#include "TString.h"
#endif

//
// Brat Classes
//

#include <BrMagnetVolume.h>
#include "BrRotMatrix.h"
#include "BrVector3D.h"
#include "BrPlane3D.h"
#include "BrUnits.h"

//Needed for MySQL db access
#include "BrRunInfoManager.h"
#include "BrGeometriesDb.h"

ClassImp(BrMagnetVolume);

//___________________________________________________________________________
 BrMagnetVolume::BrMagnetVolume()
{
  // Constructor. Set counter and list data members to zero.
  // Don't use this constructor unless you have to and know
  // what you are doing
  // Use BrMagnetVolume(Char_t*, Char_t*);

  fField = 9999;
  fCurrentRunNo = 0;
  fHallProbeList = new TObjArray();
}

//___________________________________________________________________________
 BrMagnetVolume::BrMagnetVolume(const Char_t *name, 
			       const Char_t *title, const Char_t *FileName)
  : BrDetectorVolume(name, title, FileName)

{
  // named constructor
  //

  SetDefaultCurrentParameters(name);
  fField = 9999;
  fPolarity = 0;   //KH 3-Aug-2001 since parameters not initialized to 0
  fCurrentRunNo = 0;
  fHallProbeList = new TObjArray();
}

//__________________________________________________________________________
 BrMagnetVolume::BrMagnetVolume(const Char_t *name, const Char_t *title)
  : BrDetectorVolume(name, title)
{
  // named constructor

  SetDefaultCurrentParameters(name);
  fField = 9999;
  fPolarity = 0;   //KH 3-Aug-2001 since parameters not initialized to 0
  fCurrentRunNo = 0;
  fHallProbeList = new TObjArray();
}

//__________________________________________________________________________
 BrMagnetVolume::BrMagnetVolume(const Char_t *name, TObjArray *asciiVolList)
  : BrDetectorVolume(name, asciiVolList) {
  // named constructor called by BrGeometryDbManager in MySQL mode

  SetDefaultCurrentParameters(name);
  fField = 9999;
  fPolarity = 0;   //KH 3-Aug-2001 since parameters not initialized to 0
  fCurrentRunNo = 0;
  fHallProbeList = new TObjArray();
}

//__________________________________________________________________________
 BrMagnetVolume::BrMagnetVolume(const Char_t *name, const Char_t *title, 
			       Float_t sizeX, Float_t sizeY, Float_t sizeZ,
                               BrVector3D origin, BrRotMatrix rotMatrix,
                               Float_t frontEdge, Float_t backEdge)
  : BrDetectorVolume(name,title,sizeX,sizeY,sizeZ,origin,rotMatrix) 
{
  // -------------------------------------------------------
  // Normal constructor specifying origin and rotation matrix
  // -------------------------------------------------------
  
  fEdgeFront = frontEdge;
  fEdgeBack  = backEdge;
  fField = 9999;
  fPolarity = 0;   //KH 3-Aug-2001 since parameters not initialized to 0
  fCurrentRunNo = 0;
  fHallProbeList = new TObjArray();
  SetDefaultCurrentParameters(name);
}

//__________________________________________________________________________
 BrMagnetVolume::~BrMagnetVolume() {
  // DTOR  
  fHallProbeList->SetOwner(kTRUE);
  delete fHallProbeList;
}

//__________________________________________________________________________
 void BrMagnetVolume::SetDefaultCurrentParameters(const Char_t* name)
{
  // -----------------------------------
  //  Default current to field values.
  //  RD 12/47/2000
  // -----------------------------------

  if(!strcasecmp("D5",name)){
     fA =   17.25;
     fB =    6.03;
     fC =   -0.00003;
     }
  else if(!strcasecmp("D1",name)){
     fA =  -54.2;
     fB =    3.8;
     fC =   -0.00005;
     }
  else if(!strcasecmp("D2",name)){
     fA = -106.3; 
     fB =    6.389;
     fC =   -0.00024;
     }
  else if(!strcasecmp("D3",name)){
     fA =  -24.96;        // Ramiro from 27/03/2002 (PS)
     fB =    4.251;       // Ramiro from 27/03/2002 (PS)
     fC =   -0.00004784;  // Ramiro from 27/03/2002 (PS)
     }
  else if(!strcasecmp("D4",name)){
     fA =  128.5;         // Ramiro from 21/03/2002 (PS)
     fB =    4.399;       // Ramiro from 21/03/2002 (PS)
     fC =    0.00001658;  // Ramiro from 21/03/2002 (PS)
     }
  else {
     Error("SetDefaultCurrentParameters","Invalid magnet: %s specified",name);
     }
}

//___________________________________________________________________________
 void BrMagnetVolume::ListParameters() const
{
  // ----------------------------------------------
  //  List all parameters, maybe should be changed 
  //  to Print(const Option_t*).
  //  2/22/02 - Slated to become obsolete - use Print() instead
  // ----------------------------------------------
  Warning("ListParameters","Obsolete - Use Print() instead");

  Print("d");

}

//_____________________________________________________________________________
 void BrMagnetVolume::Print(Option_t* option) const
{
  // Options:
  //   B         Basic information
  //   D         Detector information
  //
  TString opt(option);
  opt.ToLower();

  // Basic information
  if (opt.Contains("b"))
    cout << "BrMagnetVolume: " << GetName() << " - " << GetTitle()
         << endl;

  if (opt.Contains("d")) {
    const BrRotMatrix* rotm = fSystem.GetRotMatrix();

    cout << "Magnet Name is " << GetName() 
	 << " Type is : " << fFieldType << endl;
    cout << " Size" << setw(6) << fSize[0] << setw(6) 
	 << fSize[1] << setw(6) << fSize[2] << endl;
    cout << " Position" << setw(6) << fSystem.GetOrigin() << endl;
    cout << *rotm << endl;
    cout << "Effective Edges " << setw(8) << fEdgeFront 
	 << setw(8) << fEdgeBack << endl;
    cout << "Magnetic Field " << setw(8) << fField << endl;
    cout << " BdL           " << setw(8) << GetBdl() << endl;
  }
}

//___________________________________________________________________________
 Bool_t BrMagnetVolume::ReadASCIIFile(Char_t *FileName, Char_t *DetectorName)
{
  // ------------------------------------------------------------------
  //  Read Magnet parameters from a field file. Organized in a similar 
  //  way as to the geometry, but has additional information on the 
  //  field values. Each entry should have the following data.
  //  ***
  //  As of (12/11/98) GBRAHMS+gbr2c.f does not yet generate this.
  //
  //
  //  MAGNET= D5
  //  gap x        =   35.000 cm
  //  gap y        =   10.000 cm
  //  gap z        =   76.200 cm
  //  rotation ang =  34.000 deg.
  //  gap center x =  106.247 cm
  //  gap center y =    0.000 cm
  //  gap center z =  157.517 cm
  //  Type=edge
  //  Field (KG)   =   -6.00
  //  z min        =  -42.000 cm
  //  z max        =   42.000 cm
  //
  // -------------------------------------------------------------------
  
  FILE *GeoFile;
#define maxgeoline 80
  Char_t geo_line[maxgeoline];
  Char_t det_name[5];
  Float_t z_min, z_max, angle,beta;
  
  Float_t xl,yl,zl,xl_center,yl_center,zl_center, fval = fField;
  Char_t *c;
  Int_t imag;

  
  cout << "Opening Magnet file " << FileName 
       << " for " << GetName() << endl;
  if( !(GeoFile = fopen( FileName,"r"))){
    cout << "File not present " << endl;
    return kFALSE;
  }
  
  TString f(FileName);
  if (f.Contains(".geo")) {
    cout << " The magnet info is only in a *.mag file " << endl;
    return kFALSE;
  }
  while(( c = fgets(geo_line,maxgeoline,GeoFile))) {
    imag = strncmp(geo_line,"MAGNET",6);
    if( !imag ) {
      sscanf(geo_line,"MAGNET= %s",det_name);
      if(!strcmp(det_name, DetectorName)) {
	beta=0.0;   
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," gap x        = %f",&xl);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," gap y        = %f",&yl);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," gap z        = %f",&zl);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," rotation ang = %f",&angle);
	long nbytes = ftell(GeoFile);
	fgets(geo_line,maxgeoline,GeoFile);
	if (sscanf(geo_line," vertical ang = %f",&beta));         
	else
	  fseek(GeoFile, nbytes, SEEK_SET);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," gap center x = %f",&xl_center);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," gap center y = %f",&yl_center);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," gap center z = %f",&zl_center);
	fgets(geo_line,maxgeoline,GeoFile);
	char ftype[20];
	sscanf(geo_line," Type=%s",ftype);
	fFieldType = ftype;
	// get position in file
	nbytes = ftell(GeoFile);
	fgets(geo_line,maxgeoline,GeoFile);
	if (sscanf(geo_line," Field (KG)   = %f",&fval)) 
	  fField=fval;         
	else
	  fseek(GeoFile, nbytes, SEEK_SET);
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," z min        = %f",&z_min);         
	fgets(geo_line,maxgeoline,GeoFile);
	sscanf(geo_line," z max        = %f",&z_max);
	fEdgeFront = z_min;
	fEdgeBack  = z_max;

	SetVolumeParameters(xl,yl,zl,angle,beta,
			    xl_center,yl_center,zl_center,"Magnet");
	fclose(GeoFile);
	return kTRUE;
      }
      
    }
  }
  Warning("ReadASCIIFile","Did not find %s in %s", DetectorName, FileName);
  return kFALSE;
}
  

//___________________________________________________________________________
 void BrMagnetVolume::SetCurrent(const Double_t I  , const Char_t* Pol)
{
  // ---------------------------------------
  // Set field value given the intensity
  // and polarity of the current
  // --------------------------------------- 

  if(!strcmp(Pol,"A"))
    fPolarity=-1.0;
  else if(!strcmp(Pol,"B"))
    fPolarity=1.0;
  else if(!strcmp(Pol,"Off"))  //Added by KH 3-Aug-2001 for runs when mag off
    fPolarity=0.0;
  else
    {
      cerr << "illegal Polarity must by (A/B/Off)" << endl;
    }
  fField = fPolarity * (fA+fB*I+fC*I*I)/1000.0;
}

//___________________________________________________________________________
 Double_t  BrMagnetVolume::GetCurrent(const Double_t Field  )
{
  // 
  // Get the current corresponding to a Magnetic field
  //
  // --------------------------------------- 

  Double_t field = TMath::Abs(fField);
  Double_t a = fC;
  Double_t b = fB;
  Double_t c = fA-field*1000.0;
  Double_t D = b*b-4*a*c;
  if(D<0){
    Warning("GetCurrent","No solution");
    return 0;
  }
  Double_t current = (-b+TMath::Sqrt(D))/( 2.0*a);
  return current;
}


//______________________________________________________________
ostream& operator<< (ostream & os,BrMagnetVolume *volume_p)
{
  os<<"Volume Name is "<<volume_p->GetName()<<"n";
  os<<" Position :" << volume_p->fSystem.GetOrigin() << "n";
  os<<" RotMatrix     :" << volume_p->GetRotMatrix() << "n";

  os<<" Gap      :" << volume_p->GetSize()[0]<<","<<
         volume_p->GetSize()[1]<<","<<volume_p->GetSize()[2]<<")n"
    <<"Front Effective Edge:" <<volume_p->GetEffectiveEdgeEntrancePlane()<<"n"
    <<"Back Effective Edge :" <<volume_p->GetEffectiveEdgeExitPlane()<<"n"
    <<" Field    : " << volume_p->GetField() << "n"
    <<" Bdl      : " << volume_p->GetBdl() << endl;

  os << endl;
  return os;
}

//______________________________________________________________
ostream& operator<< (ostream & os,BrMagnetVolume &volume_p)
{
  os<<&volume_p;
  return os;
}

//______________________________________________________________
 BrPlane3D BrMagnetVolume::GetEffectiveEdgeEntrancePlane() 
{
  // ------------------------------------
  // return effective edge entrance plane
  // ------------------------------------

  Double_t dl = fEdgeFront;
  BrPlane3D entranceplane(0,0, dl,0,1, dl,1,0, dl);
  return entranceplane;
}

//______________________________________________________________
 BrPlane3D BrMagnetVolume::GetEffectiveEdgeExitPlane() 
{
  // ------------------------------------
  // return effective edge exit plane
  // ------------------------------------

  Double_t dl = fEdgeBack;
  BrPlane3D exitplane(0,0,dl, 0,1,dl, 1,0,dl);
  return exitplane;
}

//______________________________________________________________
 BrLine3D BrMagnetVolume::SwimBack(const BrLine3D& line,
				  const Double_t momentum) 
{
  // --------------------------------------------------------------
  // A routine to take a track (represented by a line) which begins 
  // at the back face of the magnet, use the magnetic field and 
  // momentum and return a line which contains the coordinate where 
  // the track exits the front face of the magnet and the direction 
  // rotated by the change in angle.
  // --------------------------------------------------------------
  
  Double_t   d2l,b2;
  Double_t   cs2, sin1, sin2, th1, th2, theta, cs, si, r;
  BrVector3D al,aln;
  BrVector3D xc; //Exit of magnet (where we start to swim back)
  BrVector3D xe; //Entrance of magnet (where get come out of the front)
  
  d2l = fEdgeBack;
  b2 = fField;
  
  BrPlane3D ExitPlane(0,0,d2l,0,1,d2l,1,0,d2l);
  xc = ExitPlane.GetIntersectionWithLine(line);
  al = line.GetDirection();

  if (TMath::Abs(b2)>0){ 
   // if magnetic field present

    cs2 = (Float_t)sqrt(al[0]*al[0] + al[2]*al[2]);
    sin2 = al[0] / cs2;
    sin1 = GetBdl() / (3335.6 * momentum) + sin2;
    th1   = (Float_t)TMath::ASin(sin1);
    th2   = (Float_t)TMath::ASin(sin2);
    theta = th2 - th1;

   cs    = (Float_t)TMath::Cos(theta);
   si    = (Float_t)TMath::Sin(theta);
   
   // Rotate the coordinates for (al[1],al[2]) by the scattering angle
   aln[0] = al[0] * cs - al[2] * si;
   aln[2] = al[0] * si + al[2] * cs;
   aln[1] = al[1];
   
   // These are now direction cosines.
   // Calculate the position at the entrance of the Magnet
   r = 2.0 * d2l / (sin1-sin2);
   
   Double_t xdiff = r*(Float_t)(TMath::Cos(th2) - TMath::Cos(th1));
   Double_t ydiff = TMath::Abs(theta * r / cs2) * al[1];
   

   xe[0] = xc[0] - xdiff;
   xe[1] = xc[1] - ydiff;
   xe[2] = -d2l;
   
  }
  else {
    // no magnetic field, just continue line in same direction
   
    d2l = fEdgeFront;
    BrPlane3D EntrancePlane(0,0, d2l,0,1, d2l, 1,0, d2l);
    xe = EntrancePlane.GetIntersectionWithLine(line);
    aln = al;
  }
 
 BrLine3D entrance(xe,aln);
 return entrance;
}

//______________________________________________________________
 BrLine3D BrMagnetVolume::SwimForward(const BrLine3D& line,
				     const Double_t momentum) 
{
  // --------------------------------------------------------------
  // A routine to take a track (represented by a line) which begins 
  // at the front face of the magnet, use the magnetic field and 
  // momentum and return a line which contains the coordinate where 
  // the track exits the front face of the magnet and the direction 
  // rotated by the change in angle.
  // --------------------------------------------------------------
  
  Double_t   d2l, b2;
  Double_t   cs2, sin1, sin2, th1, th2, theta, cs, si, r;
  BrVector3D al, aln;
  BrVector3D xc; // Exit of magnet (where get come out of the back)
  BrVector3D xe; // Entrance of magnet (where we start to swim back)
  BrLine3D entrance;

  d2l = fEdgeFront;
  b2  = fField;
  
  BrPlane3D EntrancePlane(0,0, d2l, 0,1, d2l,1, 0, d2l);
  xc = EntrancePlane.GetIntersectionWithLine(line);
  
  al = line.GetDirection();
  for(Int_t step=0;step<1;step++){
    Double_t Bdl;
    if(step==0) Bdl = GetBdl();
    else Bdl = GetBdl(line,entrance);

    if (TMath::Abs(b2)>0){ 
      // if magnetic field present
      
      cs2 = (Float_t)sqrt(al[0]*al[0] + al[2]*al[2]);
      sin2 = al[0] / cs2;
      sin1 = - Bdl / (3335.6 * momentum) + sin2;
      th1   = (Float_t)TMath::ASin(sin1);
      th2   = (Float_t)TMath::ASin(sin2);
      theta = th2 - th1;
      
      cs    = (Float_t)TMath::Cos(theta);
      si    = (Float_t)TMath::Sin(theta);
      
      // Rotate the coordinates for (al[1],al[2]) by the scattering angle
      aln[0] = al[0] * cs - al[2] * si;
      aln[2] = al[0] * si + al[2] * cs;
      aln[1] = al[1];
      
      // These are now direction cosines.
      // Calculate the position at the entrance of the Magnet
      r = 2.0 * d2l / (sin1-sin2);
      
      Double_t xdiff = r*(Float_t)(TMath::Cos(th2) - TMath::Cos(th1));
      Double_t ydiff = TMath::Abs(theta * r / cs2) * al[1];
      
      xe[0] = xc[0] - xdiff;
      xe[1] = xc[1] + ydiff;
      xe[2] = -d2l;
    
    }
    else {
      // no magnetic field, just continue line in same direction
      d2l = fEdgeBack;
      BrPlane3D ExitPlane(0,0,d2l,0,1,d2l,1,0,d2l);
      xe = ExitPlane.GetIntersectionWithLine(line);
      aln = al;
    }
    
    entrance.SetDirection(aln);
    entrance.SetOrigin(xe);

  }

  
  return entrance;
}

//______________________________________________________________
 Bool_t BrMagnetVolume::GetSwimStatus(const BrLine3D& FrontLine,
				     const BrLine3D& BackLine, 
				     Float_t FiduCutX,Float_t FiduCutY) 
{
  // --------------------------------------------------------
  // This method fits helix to the entry and exit line
  // and check wheter the helix run within the magnet gap
  // --------------------------------------------------------


  if(Verbose())
    cout << FrontLine << "n" << BackLine << "n" << FiduCutX << FiduCutY << endl;

  Double_t x0,z0,Radius, Radius2;

  Double_t Xgap   = *(GetSize());
  Double_t Ygap   = *(GetSize()+1);
  Double_t magLng = fEdgeBack - fEdgeFront;

  Double_t z1 = fEdgeFront;
  Double_t z2 = fEdgeBack;
  
  BrPlane3D Plane1(0,0,z1, 0,1,z1, 1,0,z1);
  BrPlane3D Plane2(0,0,z2, 0,1,z2, 1,0,z2);
  
  BrVector3D vec1 = Plane1.GetIntersectionWithLine(FrontLine);
  BrVector3D vec2 = Plane2.GetIntersectionWithLine(BackLine);
  
  Double_t x1 = vec1(0);
  Double_t y1 = vec1(1);
  Double_t x2 = vec2(0);
  Double_t y2 = vec2(1);
  Double_t Xmax = 0;
  Double_t Ymax = 0;
  Double_t Xarc, Xent;

  if (fField != 0){ //if field present
    
    Double_t dir1x = FrontLine.GetDirection()[0];
    Double_t dir1z = FrontLine.GetDirection()[2];
    Double_t size  = TMath::Sqrt(dir1x*dir1x + dir1z*dir1z);
    dir1x /= size;
    dir1z /= size;

    Double_t dir2x = BackLine.GetDirection()[0];
    Double_t dir2z = BackLine.GetDirection()[2];
    size  = TMath::Sqrt(dir2x*dir2x+dir2z*dir2z);
    dir2x /= size;
    dir2z /= size;



    // Now define helix (circle in X,Z plane) parameters: Radius2 (r^2), x0 and z0
    //

    // Calculate Radius square, x0, z0 from vector algebra
    // Note the position of (x0,z0) depends on the bending direction of the 
    // track in the magnet.
    //
    Double_t RadiusSquared = ((z2-z1)*(z2-z1)+ (x2-x1)*(x2-x1)) 
      / ((dir2z-dir1z)*(dir2z-dir1z)+(dir2x-dir1x)*(dir2x-dir1x));
    Radius = TMath::Sqrt(RadiusSquared);
    if(dir2x < dir1x)
      Radius = - Radius;

    if(Verbose())
      cout << x0 << z0 << endl;

    x0 = x1 + Radius *dir1z;
    z0 = z1 - Radius *dir1x;

    if(Verbose()){
      cout << Radius << endl;
      cout << RadiusSquared << endl;
      cout << x0 << z0 << endl;
    }


    // And now we can detemine the maximum helix distance from the
    // magnet center axis
    // Xarc is the largest (numerical value) inside the gap of the Helix
    // The Xend is the positions at the Gap - these must also be checked.
    //

    if (TMath::Abs(z0) < magLng/2.){
      Xarc = x0 - Radius;
      Xent = TMath::Max(TMath::Abs(x1),TMath::Abs(x2));
    }
    // If the z0 is outside the effective edge the points to check are
    // the entrace x1, and x2 values.
    //
    else {
      Xarc = x1;
      Xent = x2;
    }
    
  } else
    // fField=0 
    { 
      Xarc = x1;
      Xent = x2;
    }
  
  if(Verbose())
    cout << "Gap checks " << Xent <<" " <<  Xarc << endl;
  Xmax = TMath::Max( TMath::Abs(Xent), TMath::Abs(Xarc));


  if (TMath::Abs(y1) <TMath::Abs(y2))
    Ymax = y2;
  else 
    Ymax = y1;
  
  // OK, now we can check whether the helix lies within the magnet gap
  
  Bool_t TrackTransported = kFALSE;
  
  if ((Xmax < (Xgap/2.0 - FiduCutX)) &&
      (TMath::Abs(Ymax) < (Ygap/2.0 - FiduCutY)))
    TrackTransported=kTRUE;
  
  // In case of D1 we have to take into account a Cu shielding box
  // placed in the front of the magnet:
  // 
  if(TrackTransported && !strcmp("D1",GetName())){
    // These formula also assumes R<0 ie bending to right and (x0,z0) outside
    // magnet gap- This does not have to be true. Please fix.
    //
    Radius = TMath::Abs(Radius);
    Double_t outerPos = -112.7; //outer addge of the D1 front field clamp?
    Double_t innerPos = outerPos + 38.1;
    Double_t InnerX = TMath::Sqrt(Radius2 - (innerPos-z0)*(innerPos-z0)) + x0;
    Double_t OuterX = TMath::Sqrt(Radius2 - (outerPos-z0)*(outerPos-z0)) + x0;
    if (InnerX < (-3.56 + FiduCutX) || OuterX < (-1.81 + FiduCutX))
      TrackTransported=kFALSE;
   }

  return TrackTransported;
}

//______________________________________________________________
 Double_t BrMagnetVolume::GetBdl(const BrLine3D& FrontLine,
				     const BrLine3D& BackLine) 
{
  // --------------------------------------------------------
  // This method fits helix to the entry and exit line
  // calculate track lenght in the magnetic field and
  // returns Bdl 

  const Double_t pi = BrUnits::pi;
  
  Double_t z1 = fEdgeFront;
  Double_t z2 = fEdgeBack;

  BrPlane3D Plane1(0,0,z1,0,1,z1,1,0,z1);
  BrPlane3D Plane2(0,0,z2,0,1,z2,1,0,z2);

  BrVector3D vec1 = Plane1.GetIntersectionWithLine(FrontLine);
  BrVector3D vec2 = Plane2.GetIntersectionWithLine(BackLine);

  Double_t x1 = vec1.GetX();
  Double_t y1 = vec1.GetY();
  Double_t x2 = vec2.GetX();
  Double_t y2 = vec2.GetY();

  Double_t tang1 = FrontLine.GetDirection()[2]/FrontLine.GetDirection()[0];
  Double_t tang2 = BackLine.GetDirection()[2]/BackLine.GetDirection()[0];
  
  // Now define helix (cycle) parameters: Radius2 (r^2), x0 and z0
  
  Double_t z0 = (x2 - x1 - z1*tang1 + z2*tang2) / (tang2 - tang1);
  Double_t x0 = x2 + (z2 - z0)*tang2;
  Double_t Radius2  = (x1-x0)*(x1-x0) + (z1-z0)*(z1-z0);
 
  Double_t alpha1 = TMath::ATan(tang1);
  Double_t alpha2 = TMath::ATan(tang2);
  if(alpha1<0.0) alpha1=alpha1+pi;
  if(alpha2<0.0) alpha2=alpha2+pi;
  
  Double_t dl = (alpha2-alpha1)*TMath::Sqrt(Radius2);

  return fField*dl;
  
}

//_____________________________________________________________________________
 void BrMagnetVolume::Update() {
  //Do an update for a particular run.  
  //For the moment, most of the building is done in geodb manager.
  //Perhaps, it will be moved soon.  For the moment, we simply update
  //the Keithley values from the DB.

  const BrRunInfo *run = fRunManager->GetCurrentRun();
  Int_t runno = run->GetRunNo();

  if(runno == fCurrentRunNo) return;
  fCurrentRunNo = runno;

  //Check that we're connected to geometry db
  if (!fGeometryDb->IsConnected()) {
     //Try to connect to the geometry database
     if (!fGeometryDb->Connect()) {
        Warning("BuildDetectorVolume","couldn't connect to geometry database");
        return;
        }
     }

  //Check that we're connected to run db
  if (!fRunDb->IsConnected()) {
     // try to connect to the run database
     if (!fRunDb->Connect()) {
        Warning("Update", "couldn't connect to run database");
        return;
        }
     }

  //Get volume parameters from DB
  FillVolume();  //part of base class (BrDetectorVolume)

  //Fill magnet parameters from DB
  Bool_t stat = FillMagnetParameters();

  //Get list of Hall Probe readings for this run.
  BrDbRun *dbRun = fRunDb->GetRun(runno);
  //Get start and end time of run
  Int_t start  = dbRun->GetStartTime();
  Int_t end    = dbRun->GetEndTime();

  //Next two lines (FillHallProbeList and UpdateField) 
  //commented out 27-Jun-2002 because of possible problems 
  //with sorting Hall Probe list values
  //not used for the moment, so comment until we begin to use it.
  //Should investigate if order by time statement which is not necessary is
  //perhaps the problem.  Also, perhaps we should just take the first value
  //since is is supposed to be very stable.  This may or may not help with 
  //the time spent.
  //FillHallProbeList(start,end);

  //Initialize field to start of run.  That way the user
  //at least has that if he doesn't touch this anymore.
  //UpdateField(start);

  //Close the DBs so someone else can have our slot.
  fGeometryDb->Close();
  fRunDb->Close();
}

//_____________________________________________________________________
 Bool_t BrMagnetVolume::FillMagnetParameters() {
  //Fill the magnet parameters from the DB

  const BrRunInfo *run = fRunManager->GetCurrentRun();

  //Get the magnet parameters from the DB
  BrDbMagnetVolume *mag = GetMagnetWithCondition();

  if(!mag) {
     Warning("FillMagnetParameters","Parameters for magnet %s do not exist in GeometryDB",GetName());
     return 0;
     }

  //Put the magnet parameters into the magnet volume
  SetEdgeFront(mag->GetFrontEdge());
  SetEdgeBack(mag->GetBackEdge());

  //Now, need to set current.  This is a dirty way of doing this, but it 
  //should work for the moment.  This coding should probably be implemented
  //in the BrRunInfo class
  Int_t icurrent = 0;
  const Char_t *pol = 0;
  if(fName.Contains("D1",TString::kIgnoreCase)) {
     icurrent = run->GetD1Set();
     pol = run->GetD1Pol();
     }
  else if(fName.Contains("D2",TString::kIgnoreCase)) {
     icurrent = run->GetD2Set();
     pol = run->GetD2Pol();
     }
  else if(fName.Contains("D3",TString::kIgnoreCase)) {
     icurrent = run->GetD3Set();
     pol = run->GetD3Pol();
     }
  else if(fName.Contains("D4",TString::kIgnoreCase)) {
     icurrent = run->GetD4Set();
     pol = run->GetD4Pol();
     }
  else if(fName.Contains("D5",TString::kIgnoreCase)) {
     icurrent = run->GetD5Set();
     pol = run->GetD5Pol();
     }
  else {
     Warning("BuildMagnetVolume","Invalid magnet: %d",GetName());
     cout<<" Returning 0!!!"<<endl;
     return 0;
     }
  Double_t current = (Double_t)icurrent;
  SetCurrent(current,pol);
}

 BrDbMagnetVolume *BrMagnetVolume::GetMagnetWithCondition() {
  //Get detector volumes out of the DB with name like one specified and 
  //valid time less than run time. Then search through and find
  //the one valid at the latest time which is earlier than the current run.
  //We do that by looking for the smallest difference between the start of
  //validity and the run time.

  const BrRunInfo *run = fRunManager->GetCurrentRun();

  Int_t runTime = run->GetUnixStartTime();
  Char_t condition[80];
  sprintf(condition,"validStart <= %d AND MagnetName like '%s'",runTime,GetName());

  TObjArray *arr = fGeometryDb->GetXMagnetVolume(condition);
  if(!arr) {
     Warning("GetMagnetVolumeWithCondition","Magnet: No entries found");
     return 0;
     }

  BrDbMagnetVolume *retVol = 0;
  Int_t diff;
  UInt_t big = 1<<31;
  Int_t minDiff = big - 1;  //time difference should not be larger than that!!!
  Int_t maxRevision = 0;
  TIter next(arr);
  BrDbMagnetVolume *volTmp;
  while((volTmp = (BrDbMagnetVolume*)next())) {
     diff = runTime - volTmp->GetValidStart();
     if(diff < 0) {
        //Be safe; should never come here because of condition specified above
        printf("diff < 0!!!; something is wrong; check it outn");
        }

     Int_t revision = volTmp->GetRevisionId();
     if(diff < minDiff) {
        minDiff = diff;
	retVol = volTmp;
        maxRevision = revision;
        }
     else if(diff == minDiff) {
        //Case if we have more than one that started at same time.
        //Pick one with largest revision
        if(maxRevision < revision) {
           retVol = volTmp;
           maxRevision = revision;
           }
        }
     }
  //Need to create new one copied from old one since old one will be deleted
  //when we delete arr.
  if(retVol) retVol = new BrDbMagnetVolume(*retVol);
  else {
      Warning("GetMagnetWithCondition","Found no entries for %s that started before run %d",GetName(),run->GetRunNo());
     }
  delete arr;

  return retVol;
}

//______________________________________________________________
 void BrMagnetVolume::FillHallProbeList(Int_t start, Int_t end) {
  //Fill the Hall probe list with readings during this run.

  //Get Hall probe values for magnets during this run
  //First, delete previous ones.
  fHallProbeList->SetOwner(kTRUE);
  fHallProbeList->Delete();

  //Get them out of the DB

  Int_t unit,channel;
  if(fName.Contains("D1",TString::kIgnoreCase)) {
     unit    = kUnitD1;
     channel = kChannelD1;
     }
  else if(fName.Contains("D2",TString::kIgnoreCase)) {
     unit    = kUnitD2;
     channel = kChannelD2;
     }
  else if(fName.Contains("D3",TString::kIgnoreCase)) {
     unit    = kUnitD3;
     channel = kChannelD3;
     }
  else if(fName.Contains("D4",TString::kIgnoreCase)) {
     unit    = kUnitD4;
     channel = kChannelD4;
     }
  else if(fName.Contains("D5",TString::kIgnoreCase)) {
     unit    = kUnitD5;
     channel = kChannelD5;
     }
  else {
     Fatal("Update","Invalid magnet %s",GetName());
     }

  fHallProbeList = fRunDb->GetXConditionsKeithley(unit,channel,start,end);
}

//______________________________________________________________
 void BrMagnetVolume::UpdateField(Int_t time) {
  //This is the routine one would use to update the field based
  //on the hall probe readings.
  //Search through the list and take the last value that comes before
  //time

  TIter nextHallProbe(fHallProbeList);
  BrDbConditionsKeithley *hallProbe = 0;

  if(fHallProbeList->GetEntries() > 0) {
     hallProbe = (BrDbConditionsKeithley*)fHallProbeList->At(0);
     if((time + 200) < hallProbe->GetTime()) {
        Warning("UpdateField","%d is inappropriate time for this run, min is %d",time,hallProbe->GetTime());
        return;
        }
     }
  else {
     Warning("UpdateField","No entries in Hall Probe List!; check it out");
     }

  Int_t count = 0;
  Float_t value;
  while((hallProbe = (BrDbConditionsKeithley*)nextHallProbe())) {
     if(time < hallProbe->GetTime()) {
        value = hallProbe->GetValue();
        SetFieldFromHallProbe(value);
        return;
        }
     count++;
     }

  hallProbe = (BrDbConditionsKeithley*)fHallProbeList->Last();

  if(time - 200 > hallProbe->GetTime()) {
     Warning("UpdateField","%d is inappropriate time for this run, max is %d",time,hallProbe->GetTime());
     return;
     }

  //Set field to last one in list
  SetFieldFromHallProbe(hallProbe->GetValue());

}

 void BrMagnetVolume::SetFieldFromHallProbe(Float_t hallProbeValue) {
  //Set the field given the value of the hall probe reading

  //printf("New Field to be set to field for Hall Probe value = %f once calibration knownn",hallProbeValue);
}

//______________________________________________________________
//
// $Log: BrMagnetVolume.cxx,v $
// Revision 1.21  2002/08/30 17:35:06  videbaek
// Add Verbose getter method in DetectorVolume.
// Corrected the checkswim status where the code was wrong for tracks that bends
// left, as well as given Nan for straigt incidence tracks.
//
// Revision 1.20  2002/08/08 15:22:13  ufstasze
// Introduced x and y fiducial cut in GetSwimStatus
//
// Revision 1.19  2002/06/27 22:16:52  hagel
// Removed calls to FillHall probe values
//
// Revision 1.18  2002/06/20 01:30:44  ouerdane
// fixed polarity and current setting in FillMagnetParameters
//
// Revision 1.17  2002/06/06 23:04:22  hagel
// Fix small bugs with magnet revisions
//
// Revision 1.16  2002/04/22 13:14:36  staszel
// GetSwimStatus: introduced a copper shielding in the front of D1.
//
// Revision 1.14  2002/04/16 14:44:12  hagel
// Implement Hall Probe reading from Db in ySQL mode.  Major surgery on BrGeometryDbManager concerning building BrDetectorVolume and BrMagnetVolume
//
// Revision 1.13  2002/04/10 13:03:45  ufstasze
// Updated parameters for B vs. I for D3 and D4.
// New parameters based on Ramiro measurements from March 21 and 27, 2002.
//
// Revision 1.12  2002/04/10 09:38:06  ouerdane
// added rotmatrix in Print
//
// Revision 1.11  2002/02/24 20:31:58  videbaek
// insignificant code cleaning
//
// Revision 1.10  2002/02/22 21:49:15  videbaek
// Add Print method, and give warning for ListParameters as becoming obsolete.
//
// Revision 1.9  2002/02/08 22:55:48  hagel
// Take advantage of new features of BrRotMatrix
//
// Revision 1.8  2001/12/13 12:39:34  ouerdane
// Replaced physical gap length by effective edge gap length in GetSwimStatus
//
// Revision 1.7  2001/11/05 23:41:42  hagel
// Changes to MySQL mode for Geometry DB manager
//
// Revision 1.6  2001/09/24 14:00:07  staszel
// Small correction to GetSwimStatus that allows this method
// to deal with zero magnetic fields.
//
// Revision 1.5  2001/09/22 16:18:18  videbaek
// Commit changes to BrDetectorVolume and BrMagnetVolume that
// Pawel has made. Check out with test programs as well as reconstruction so declared ok.
//
// Revision 1.3  2001/08/03 09:19:09  hagel
// Small iteration on Geometry DB stuff
//
// Revision 1.2  2001/07/22 21:32:32  videbaek
// Added method GetCurrent
//
// Revision 1.1.1.1  2001/06/21 14:55:18  hagel
// Initial revision of brat2
//
// Revision 1.19  2001/06/21 09:40:07  ouerdane
// added some checks in the magnet file reading in ReadASCIIFile:
// if the returned value of sscanf of the line "Field (kG) = ..." is not zero,
// then, read the field value. Otherwise, return to the previous
// line and read the rest. This way, fField keeps its default
// value set to 9999. The reason is to make a check in the global
// tracking classes. If the field has this value, try to retrieve the
// right one from the database. If there's no connection to the run
// database, then the program stops.
//
// It means that if you have a dummy value in the mag file, remove it and
// put the right one or use the database instead: in this case, remove
// the line with "Field (kG) = ..." in the mag file.
//
// Other change: if the file ends by .geo, ReadASCIIFile returns kFALSE.
// The magnet info should only be in a .mag file.
//
// All of this will soon become obsolete but important for "old-fashioned"
// analyses.
//
// Revision 1.18  2001/05/07 21:17:21  hagel
// Changes to implement MySQL Db stuff
//
// Revision 1.17  2001/03/07 17:36:47  hagel
// Changes to use with new MySQL DB access
//
// Revision 1.16  2001/01/01 20:47:18  bramreco
// Add BdL to output in ListParameters
//
// Revision 1.15  2000/12/27 21:36:47  videbaek
// Cosmetic- added checks for non-existing modules added.
//
// Revision 1.14  2000/12/21 14:37:53  videbaek
// Convert current calculated field into kGauss
//
// Revision 1.13  2000/12/21 14:13:21  videbaek
// The sign was not set in SetCurrent ..fix- oops
//
// Revision 1.12  2000/12/16 01:12:54  videbaek
// Set proper types for methods.
//
// Revision 1.11  2000/12/07 22:12:52  videbaek
// Added current setting capabilities
//
// Revision 1.10  2000/12/06 21:03:50  videbaek
// Fix sign error in BrEntrance Plane.
//
// Revision 1.9  2000/11/22 21:04:48  videbaek
// BrMagnetVolume is now derived from BrDetectorVolume. Modified and uniform methods
// now.
//
// Revision 1.8  2000/11/15 20:58:01  videbaek
// Added SwimForward to magnet volume. Modified internals. The existing
// Get methods are stillvalid. Some Set methods has been added.
//
// Revision 1.7  2000/10/09 20:48:20  videbaek
// Fix a small error in swimback. The entrance point was set at the nominal
// magnet gap edge, not the effective edge.
// Moved CVS comments to end of code.
//
// Revision 1.6  2000/06/21 20:42:10  trine
// Minor change in BrMagnetVolume::Swimback() - if no magnetic field, just
// continue in a straight line through magnet.
//
// Revision 1.5  2000/05/02 13:34:21  videbaek
// removed excessive log comments
//
// Revision 1.4  1999/04/22 21:35:23  hagel
// Improvements in SwimBack()
//
// Revision 1.3  1999/03/07 00:00:42  hagel
//  many changes
//
// Revision 1.2  1998/12/21 20:18:32  videbaek
// Added magnet voluems. Additional features for Modules.
// New BrMatch intended to replace TSonataMath. Some changes in
// matrix routines.
//
//

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