Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

BField.cxx

Go to the documentation of this file.
00001 
00002 // $Id: BField.cxx,v 1.36.2.1 2008/02/13 16:44:52 scavan Exp $
00003 //
00004 // BField
00005 //
00006 // Implementation code for BField
00007 //
00008 // Author:  R. Hatcher 2000.06.20
00009 //
00011 #include "BField/BField.h"
00012 
00013 #include "BField/BfldLoanPool.h"
00014 #include "BField/BfldHandlerRect2d.h"
00015 #include "BField/BfldHandlerVoronoi.h"
00016 #include "BField/BfldCache.h"
00017 #include "BField/BfldMap.h"
00018 #include "DcsUser/CoilTools.h"
00019 
00020 #include "TMath.h"
00021 
00022 #include "MessageService/MsgService.h"
00023 CVSID("$Id: BField.cxx,v 1.36.2.1 2008/02/13 16:44:52 scavan Exp $");
00024 
00025 ClassImp(BField)
00026 
00027 #include <cassert>
00028 #include <iomanip>
00029 
00030 const Int_t kNoMapUsed = -9999;
00031 static const TVector3 zeroBfld(0.,0.,0.);
00032 
00033 #if 0
00034 static std::ostream& operator<<(std::ostream& os, const TVector3& tv3)
00035 {
00036   int w=9, p=4; // 1mm precision
00037   int prec = os.precision();
00038   os << "[" << setw(w)   << setprecision(p) << tv3.x()
00039      << "," << setw(w)   << setprecision(p) << tv3.y()
00040      << "," << setw(w+1) << setprecision(p) << tv3.z()
00041      << "]";
00042    os << resetiosflags(ios::floatfield);  // reset to "%g" format
00043    os << setprecision(prec);  // restore precision
00044   return os;
00045 }
00046 #endif
00047 
00048 //_____________________________________________________________________________
00049 BField::BField()
00050   : fLoanPool(0), fHandler(0), fCache(0), 
00051     fCurrentPlaneMap(0), fOwnedPlaneMap(0)
00052 
00053 { 
00054    // Default constructor -- needed if classes are to inherit this interface
00055    Init(); 
00056    InitFlagsFromLoanPool();
00057    fNoField        = true;
00058 }
00059 
00060 //_____________________________________________________________________________
00061 BField::BField(VldContext vldc, Int_t coarseness, Int_t useEverywhere)
00062   : fNoField(false), fVldContext(vldc), fLoanPool(0), fHandler(0), fCache(0),
00063     fPowerOff(false), fDegaussed(false), fCoilCurrent(0),
00064     fCurrentPlaneMap(0), fOwnedPlaneMap(0)
00065 {
00066    // constructor
00067    //
00068    // "useEverywhere" is a temporary ruse for bypassing the need
00069    // for geometry during development, it assumes that a old 2d rectangular
00070    // grid is relevant *everywhere* and this is the ID.
00071    //
00072    // coarseness should be set to -1 to use a rectangular grid, in which
00073    // case useEverywhere should specify which of the old IDs to use.
00074 
00075    Init();
00076    InitFlagsFromLoanPool();
00077    fUseEverywhere = useEverywhere;
00078 
00079    // set VldRange
00080    VldTimeStamp start = VldTimeStamp::GetBOT();
00081    VldTimeStamp end   = VldTimeStamp::GetEOT();
00082    fVldRange = VldRange(vldc.GetDetector(),
00083                         vldc.GetSimFlag(),
00084                         start,
00085                         end,
00086                         "fake");
00087 
00088    if (vldc.GetDetector() == Detector::kCalDet) {
00089      fNoField = true;
00090      return;
00091    }
00092 
00093    // set the grid and attach appropriate handler
00094    // do this before we decide about UseEverywhere
00095    // (which might screw up the VldContext)
00096    SetGridHandler(vldc.GetDetector(),coarseness);   
00097 
00098    // have we been told by the package config to always
00099    // use a particular map?
00100    int forceEverywhere = fLoanPool->GetForceUseEverywhere();
00101    if (forceEverywhere) {
00102      if ( forceEverywhere == 1 ) {
00103        // special case 1 is not a particular map but to use
00104        // the code's choice of "best for this VldContext".
00105        forceEverywhere = BfldCache::GetDefaultMapVariant(fVldContext);
00106        MAXMSG("Bfld",Msg::kInfo,5)
00107          << "Bfield::ctor BfldLoanPool forceUseEverywhere=1"
00108          << " yields map " << forceEverywhere << " for "
00109          << endl << "    " << vldc.AsString("c") << "."
00110          << endl;
00111      }
00112      MAXMSG("Bfld",Msg::kInfo,5)
00113        << "BField::ctor useEverywhere was " << fUseEverywhere
00114        << ", forced by BfldLoanPool config to use "
00115        << forceEverywhere << "."
00116        << endl;
00117      fUseEverywhere = forceEverywhere;
00118    }
00119 
00120    // if we've been told to use a particular map (either from the
00121    // ctor args or from the package config), have we been
00122    // told by the package config to ignore this?
00123    if (fUseEverywhere) {
00124      int ignore = fLoanPool->GetIgnoreUseEverywhere();
00125      MAXMSG("Bfld",Msg::kInfo,5) 
00126        << "BField::ctor useEverywhere=" << fUseEverywhere
00127        << ((ignore)?" (now ignored)":" (active)") << "."
00128        << endl;
00129      if (ignore) fUseEverywhere = 0;
00130      else {
00131        // use fOwnedPlaneMap for keeping "everwhere" info
00132        fOwnedPlaneMap->SetMapVariant(0,fUseEverywhere);
00133        fOwnedPlaneMap->SetScale(0,1.0);
00134        fVldContext = VldContext();  // !NOTE! mucking up VldContext!
00135        MAXMSG("Bfld",Msg::kInfo,5) 
00136          << "BField::ctor setting fake VldContext to avoid "
00137          << "pulling geometry tables from DBI."
00138          << endl;
00139      }
00140    }
00141 
00142    // attach an appropriate cache we get from a loan pool
00143    // also look up coil current info
00144    ResetVldContext(vldc);
00145 
00146 }
00147 
00148 //_____________________________________________________________________________
00149 BField::BField(const BField& that)
00150   : TObject(that)
00151 {
00152   // (deep) copy ctor accounts for keeping ref counts straight
00153   *this = that; 
00154 }
00155 
00156 //_____________________________________________________________________________
00157 BField& BField::operator=(const BField& that)
00158 {
00159    // assignment operator (deep)
00160 
00161    if ( this == &that ) return *this;  // do nothing if asked to self-assign
00162    TObject::operator=(that);
00163 
00164    // delete owned handler, decrement cache reference
00165    fLoanPool = 0;
00166    if (fHandler) { delete fHandler;        fHandler = 0; }
00167    if (fCache)   { fCache->DecrementRef(); fCache = 0; } // not owned, can't delete it
00168 
00169    Init();
00170 
00171    // copy data
00172    fNoField             = that.fNoField;
00173    fVldContext          = that.fVldContext;
00174    fVldRange            = that.fVldRange;
00175    fLastMapVariant      = that.fLastMapVariant;
00176 
00177    fDoBHCorrection      = that.fDoBHCorrection;
00178    fDoSlotCorrection    = that.fDoSlotCorrection;
00179    fDoInterPlaneField   = that.fDoInterPlaneField;
00180    fDoSMGapAndEndField  = that.fDoSMGapAndEndField;
00181 
00182    fUseDCSCoilDir       = that.fUseDCSCoilDir;
00183    fApplyBdotScale      = that.fApplyBdotScale;
00184 
00185    fUseEverywhere       = that.fUseEverywhere; 
00186    fNoFieldBeyondZ      = that.fNoFieldBeyondZ;
00187 
00188    // attach the same cache as the copy-ee
00189    if ( that.fCache ) {
00190      fCache = that.fCache;
00191      fCache->IncrementRef();
00192    }
00193    else {
00194      // hey! this shouldn't happen
00195      assert(0);
00196    } 
00197 
00198    // translate chosen grid back into coarseness
00199    Int_t coarseness = BfldGrid::GetCoarseness(that.fGrid);
00200 
00201    // set the grid and attach appropriate handler
00202    SetGridHandler(fVldContext.GetDetector(),coarseness);
00203 
00204    fHandler->SetCache(fCache);
00205    fHandler->SetLastPolygAsSeed();
00206 
00207    return *this;
00208 }
00209 
00210 //_____________________________________________________________________________
00211 void BField::ResetVldContext(const VldContext& vldc)
00212 {
00213    // for any given VldContext we *should* look up coil status + current
00214  
00215    fVldContext = vldc;
00216    Detector::Detector_t det = vldc.GetDetector();
00217 
00218    VldTimeStamp start = VldTimeStamp::GetBOT();
00219    VldTimeStamp end   = VldTimeStamp::GetEOT();
00220    fVldRange = VldRange(det,vldc.GetSimFlag(),start,end,"");
00221 
00222    if (!fHandler) SetGridHandler(vldc.GetDetector(),-1);
00223 
00224    if (fCache) fCache->DecrementRef(); // unreference previous cache, if any
00225    
00226    // attach a cache we get from a loan pool
00227    fCache = fLoanPool->GetCache(fVldContext);
00228    fCache->IncrementRef();  // let cache know we have a pointer to it
00229    fVldRange.TrimTo(fCache->GetVldRange());
00230 
00231    fHandler->SetCache(fCache);
00232    fHandler->SetLastPolygAsSeed();
00233 
00234    fNoField   = false;
00235    fPowerOff  = false;
00236    fDegaussed = false;
00237 
00238    // here we determine the coil current and whether the detector
00239    // is degaussed (if I=0).  Do it early as special cases 
00240    // (eg. collar/coil or interplane ) might need it.
00241 
00242    // rwh: for now we just say get ready to multiply by 1.0
00243    switch (fVldContext.GetDetector()) {
00244    // nominal values in Amp-turns
00245    case Detector::kNear: fCoilCurrent = 40.0 * 1000.; break;
00246    case Detector::kFar:  fCoilCurrent = 15.2 * 1000.; break;
00247    default: fCoilCurrent = 0.0; fNoField = true;
00248    }
00249    // should scale fCoilCurrent by ratio of readback to nominal
00250    // from DCS readback for non-saturated part of field ...
00251 
00252    if (fUseDCSCoilDir == 1 || fUseDCSCoilDir == 2 ) {
00253      if ( ! CoilTools::IsOK(vldc))        fCoilCurrent = 0.0;
00254      else if (CoilTools::IsReverse(vldc)) fCoilCurrent = -fCoilCurrent;
00255    }
00256 }
00257 
00258 //_____________________________________________________________________________
00259 void BField::Init()
00260 {
00261    // initialize member data
00262    fNoField        = false;
00263    fVldRange       = VldRange();
00264    fGrid           = BfldGrid::kUndefined;
00265    fLastMapVariant = kNoMapUsed;
00266    fUseEverywhere  = 0; 
00267 
00268    // get access to the BfldLoanPool
00269    if (!fLoanPool) fLoanPool = BfldLoanPool::Instance();
00270 
00271    if (fOwnedPlaneMap) { delete fOwnedPlaneMap;  fOwnedPlaneMap = 0; }
00272    fOwnedPlaneMap = new BfldDbiPlaneMap;
00273 }
00274 
00275 //_____________________________________________________________________________
00276 void BField::InitFlagsFromLoanPool()
00277 {
00278    // initialize member data from loan pool
00279 
00280    // get access to the BfldLoanPool
00281    if (!fLoanPool) fLoanPool = BfldLoanPool::Instance();
00282 
00283    fDoBHCorrection      = fLoanPool->GetDefaultDoBHCorrection();
00284    fDoSlotCorrection    = fLoanPool->GetDefaultDoSlotCorrection();
00285    fDoInterPlaneField   = fLoanPool->GetDefaultDoInterPlaneField();
00286    fDoSMGapAndEndField  = fLoanPool->GetDefaultDoSMGapAndEndField();
00287 
00288    fUseDCSCoilDir       = fLoanPool->GetDefaultUseDCSCoilDir();
00289    fApplyBdotScale      = fLoanPool->GetDefaultApplyBdotScale();
00290 
00291    fNoFieldBeyondZ      = fLoanPool->GetDefaultNoFieldBeyondZ();
00292 }
00293 
00294 //_____________________________________________________________________________
00295 BField::~BField()
00296 {
00297    // destructor
00298 
00299    if (fHandler)       { delete fHandler;        fHandler = 0; }
00300    // fCache is not owned, can't delete it just change ref count
00301    if (fCache)         { fCache->DecrementRef(); fCache = 0; } 
00302    if (fOwnedPlaneMap) { delete fOwnedPlaneMap;  fOwnedPlaneMap = 0; }
00303 
00304 }
00305 
00306 //_____________________________________________________________________________
00307 void BField::SetInterpMethod(BfldInterpMethod::InterpMethod_t method)
00308 {
00309    // pass on interpolation method message to BFLHandler
00310    if (fHandler) fHandler->SetInterpMethod(method);
00311 }
00312 
00313 //_____________________________________________________________________________
00314 void BField::SetGridHandler(Detector::Detector_t detector, Int_t coarseness)
00315 {
00316    // translate Detector and "coarseness" into Grid enum
00317    fGrid = BfldGrid::GetGrid(detector,coarseness);
00318    
00319    // attach a BfldHandler (delete old if there is one)
00320    if (fHandler) { delete fHandler; fHandler = 0; }
00321 
00322    // check for special case of "rect2d" grid request
00323    if ( BfldGrid::kRect2dGrid == fGrid ) {
00324       // attach a special handler
00325       fHandler = new BfldHandlerRect2d;
00326    } else {
00327       fHandler = new BfldHandlerVoronoi;
00328    }
00329 
00330    // set the default interpolation method
00331    // BField's method simply passes on message to BFLHandler
00332    SetInterpMethod(BfldInterpMethod::kDefault);
00333 
00334    fLastMapVariant = kNoMapUsed;
00335 
00336 }
00337 
00338 //_____________________________________________________________________________
00339 TVector3 BField::GetBField(TVector3& posGlobal, Bool_t isUVZ)
00340 {
00341    // Return the magnetic field for any point in space
00342    // for the currently configured detector
00343    // if isUVZ position is in 
00344 
00345    if (fNoField) return zeroBfld;
00346 
00347    if (posGlobal.Z() > fNoFieldBeyondZ ) return zeroBfld;
00348 
00349    // stash this way for special cases ( coil, SM gap, interplane )
00350    fPositionIsUVZ = isUVZ;
00351    
00352    bool isPosSteelUVZ = isUVZ;
00353    int doLocalTransform = 0;
00354 
00355    if ( fDegaussed && fCoilCurrent == 0 ) return zeroBfld;
00356 
00357    bool was_in_steel = true;
00358 
00359    // calculate which plate (if any) this "z" corresponds to
00360    if (fUseEverywhere) {
00361 
00362      MAXMSG("Bfld",Msg::kWarning,4) 
00363        << "BField::GetBField no coil region handling or " << endl
00364        << "map selection based on plane with useEverywhere=" 
00365        << fUseEverywhere << "."
00366        << endl;
00367      fCurrentPlaneMap = fOwnedPlaneMap;
00368 
00369    } else {
00370 
00371       // check for special cases of geometry (via cache)
00372       //  0 =: don't check, outside steel use either 
00373       //       none (no InterPlaneField) or interplane gap map
00374       // <0 =: check position, but use zero when up/down/gap
00375       // >0 =: check position, try best to model field
00376       if ( fDoSMGapAndEndField ) {
00377         Ugli::SMRegion_t ismregion = fCache->InSMRegion(posGlobal,isUVZ);
00378         if ( ismregion != Ugli::kInSM1 && ismregion != Ugli::kInSM2 ) {
00379           // in SM gap or beyond SM ends
00380           if ( fDoSMGapAndEndField < 0 ) return zeroBfld; // no attempt to model
00381           return SMGapAndEndField(posGlobal,ismregion);
00382         }
00383       }
00384 
00385       // use geometry (via cache) to determine plane
00386       fCurrentPlaneMap = fCache->FindPlaneMap(posGlobal);
00387       was_in_steel = fCache->FindWasInSteel(true);
00388       // check that there was data
00389 
00390       if ( ! fCurrentPlaneMap ) {
00391         // nope?  probably because lacking BfldDbiPlaneMap table
00392         // fake something up to mimic old behaviour
00393         Int_t    imap  = BfldCache::GetDefaultMapVariant(fVldContext);
00394         Double_t scale = BfldCache::GetDefaultScale(fVldContext);
00395         MAXMSG("Bfld",Msg::kInfo,5)
00396           << "GetDefault(MapVariant,Scale) returned (" 
00397           << imap << "," << scale << ")"
00398           << ", called because missing BfldDbiPlaneMap?"
00399           << endl;
00400         fOwnedPlaneMap->SetMapVariant(0,imap);
00401         fOwnedPlaneMap->SetScale(0,scale);   
00402         fCurrentPlaneMap = fOwnedPlaneMap;
00403       }
00404    }
00405 
00406    // by default use the full plane map pair
00407    Int_t indxpair = BfldDbiPlaneMap::kFullSteelA;
00408 
00409    TVector3 posSteel(posGlobal);
00410    doLocalTransform = fCache->GetDoLocalTransform();
00411    if (doLocalTransform > 0) {
00412      posSteel = fCache->GetPositionInSteel();
00413      //if (doLocalTransform > 1) isPosSteelUVZ = false;
00414    }
00415    bool indetail = fCurrentPlaneMap->IsInDetail(posSteel.x(),posSteel.y());
00416 
00417    if ( ! was_in_steel ) {
00418      //
00419      // what to do if not (considered) in the steel
00420      //
00421      // if asked to do nothing ... return zero field
00422      if ( 0 == fDoInterPlaneField ) return zeroBfld;
00423      indxpair = BfldDbiPlaneMap::kDetailGapA;  // default to gap detail map
00424      if ( ! indetail ) {
00425        // not in detail region?
00426        if ( 3 == fDoInterPlaneField ) return zeroBfld;
00427        indxpair = BfldDbiPlaneMap::kFullGapA;
00428        // fall back to line current if no full gap map exists
00429        if (fCurrentPlaneMap->IsPairNull(indxpair) || 
00430            2 == fDoInterPlaneField) {
00431          TVector3 posCoil = posSteel; // for now!!
00432          TVector3 blinesrc = BFromLineSource(posCoil,fCoilCurrent);
00433          // if ( coil_sign_reversed ) blinesrc *= -1.0;
00434          return blinesrc;
00435        }
00436      }
00437    } else {
00438      //
00439      // what to do if (considered) in the steel
00440      // set the right map pair for the conditions and position
00441      //
00442      if ( fPowerOff ) indxpair = BfldDbiPlaneMap::kPowerOffA;
00443      else if ( indetail ) {
00444        indxpair = BfldDbiPlaneMap::kDetailSteelA;
00445        if (fCurrentPlaneMap->IsPairNull(indxpair)) 
00446          indxpair = BfldDbiPlaneMap::kFullSteelA; // no detail map, revert
00447      }
00448    }
00449 
00450    Bool_t isnull[2];  // check if scale or mapVariant is 0
00451    isnull[0] = fCurrentPlaneMap->IsNull(indxpair);
00452    isnull[1] = fCurrentPlaneMap->IsNull(indxpair+1);
00453 
00454    Double_t coilCurrMap[2] = { 0, 0 };
00455 
00456    if ( isnull[0] && isnull[1] ) return zeroBfld;  // I've got nut'n
00457 
00458    TVector3 bfieldSum(zeroBfld);  // start with zero field
00459 
00460    for (UInt_t iv = 0; iv<2; ++iv) {  // loop over 2 possible contributions
00461 
00462      if ( isnull[iv] ) continue; // no contribution
00463      
00464      // variant refers to (in part) the steel chemistry
00465      // end-plate info to get right "variant"
00466      Int_t mapVariant  = fCurrentPlaneMap->GetMapVariant(indxpair+iv);
00467      Double_t scaleMap = fCurrentPlaneMap->GetScale(indxpair+iv);
00468      // if using DCS for sign, then ignore sign associated with scale
00469      if ( (fUseDCSCoilDir&1) ) scaleMap = TMath::Abs(scaleMap);
00470 
00471      // this should never happen
00472      if (mapVariant == 0) {
00473        MAXMSG("Bfld",Msg::kInfo,5)
00474          << "BField mapVariant=0 indxpair=" << indxpair << " iv=" << iv
00475          << " isnull=" << (isnull[iv]?"true":"false")
00476          << " scaleMap=" << scaleMap
00477          << endl;
00478        MAXMSG("Bfld",Msg::kInfo,5) << *fCurrentPlaneMap << endl;
00479        continue;
00480      }
00481 
00482      BfldMap* bmap = SetupHandlerForMap(mapVariant);
00483  
00484      coilCurrMap[iv] = bmap->GetGeneratedCoilCurrent();
00485      Double_t scaleCoil = fCoilCurrent/coilCurrMap[iv]; 
00486      // probably this effect isn't linear when field is saturated...
00487      Double_t scale = scaleCoil * scaleMap;
00488      //MAXMSG("Bfld",Msg::kDebug,5)
00489      //  << "Bfld scaleCoil " << scaleCoil << " CoilCurrent " << fCoilCurrent
00490      //  << " MapCurrent " << coilCurrMap[iv] << endl;
00491 
00492      // The handler is now configured ... interogate it for the field
00493      bfieldSum += (scale*fHandler->GetBField(posSteel,isPosSteelUVZ));
00494 
00495    } 
00496 
00497    if ( was_in_steel && doLocalTransform > 1 ) {
00498      // get the steel, to tranform B_local to B_global
00499      // note Ugli uses globalInXYZ, while BField uses isUVZ
00500      // always pass true here ... don't double rotate!
00501      UgliSteelPlnHandle usph = fCache->GetCurrentSteelPlnHandle();
00502      bfieldSum = usph.LocalToGlobalVect(bfieldSum,true);
00503    }
00504 
00505    // should these be done by the handler on the pre-(scaled&summed)
00506    // version before summing? i.e. which is more correct:
00507    //  (a)  bhcorr(slotcor(map0))*scale0 + bhcorr(slotcor(map1))*scale1
00508    //  (b)  bhcorr(slotcor(map0*scale0 + map1*scale1))
00509    // this choice is (b) otherwise we should move these to the 
00510    // BfldHandler and make it aware of the flags and initialize
00511    // it with the fCurrentPlaneMap so it can pick up the parameters
00512 
00513    if      ( fDoSlotCorrection   ) ApplySlotFactorCorr(bfieldSum);
00514    if      ( fDoBHCorrection < 0 ) ApplyBHFactorCorr(bfieldSum);
00515    else if ( fDoBHCorrection > 0 ) ApplyBHCurveCorr(bfieldSum);
00516 
00517    if ( fApplyBdotScale ) {
00518      // don't apply to the gap cases
00519      if ( indxpair < BfldDbiPlaneMap::kDetailGapA ) {
00520        Double_t bdot = fCurrentPlaneMap->GetBdotScale();
00521        // don't apply if for some reason bdot value is == 0 (bad DB value)
00522        if (bdot == 0.0) {
00523          MAXMSG("Bfld",Msg::kWarning,5)
00524            << " BdotScale was zero for plane " << fCurrentPlaneMap->GetPlaneId()
00525            << "." << endl;
00526        } else {
00527          bfieldSum *= bdot;
00528        }
00529      }
00530    }
00531 
00532    return bfieldSum;
00533 }
00534                                 
00535 //_____________________________________________________________________________
00536 BfldMap* BField::SetupHandlerForMap(Int_t mapVariant)
00537 {
00538   // Ensure that the BfldHandler is properly configured
00539   // 
00540   if ( fLastMapVariant != mapVariant ) {
00541     //
00542     // map and/or grid has changed ... reinitialize handler
00543     //
00544 
00545     // Get the right base field map
00546     BfldMap  *bmap = fLoanPool->GetMap(fGrid,mapVariant);
00547     fHandler->SetMap(bmap);
00548     
00549     // Get the right Mesh diagram from the LoanPool
00550     // Give our BfldHandler a pointer to the v-diagram
00551     BfldMesh *mesh  = fLoanPool->GetMesh(fGrid,mapVariant);
00552     fHandler->SetMesh(mesh);
00553     
00554     
00555     fLastMapVariant = mapVariant;
00556     
00557   }  // map variant configured
00558   
00559   return fHandler->GetMap();
00560 }
00561 
00562 //_____________________________________________________________________________
00563 void BField::ApplySlotFactorCorr(TVector3& b)
00564 {
00565   //
00566   // Slot (gap) correction formula:
00567   //
00568   //
00569   //   B'  =   Bo                                 for Bo > Bcut
00570   //           Bo [ 1 - D * ( 1 - Bo/Bcut )^2 ]   
00571   //
00572 
00573 #ifdef DEBUG
00574   MAXMSG("Bfld",Msg::kInfo,20) 
00575     << "ApplySlotFactorCorr " 
00576     << " SlotFactor " << fCurrentPlaneMap->GetSlotFactor()
00577     << " SlotCutoff " << fCurrentPlaneMap->GetSlotCutoff()
00578     << " mag " << b.Mag()
00579     << endl;
00580 #endif
00581 
00582   Double_t slotfactor = fCurrentPlaneMap->GetSlotFactor();
00583   if ( slotfactor == 0 ) return;
00584   
00585   Double_t slotcutoff = fCurrentPlaneMap->GetSlotCutoff();
00586   if ( slotcutoff == 0 ) return;
00587      
00588   Double_t magbfld    = b.Mag();
00589   if ( magbfld > slotcutoff ) return;
00590      
00591   Double_t inner = 1.0 - magbfld/slotcutoff;
00592   Double_t slotscale = 1.0 - slotfactor * inner*inner;
00593 
00594 #ifdef DEBUG
00595   MAXMSG("Bfld",Msg::kInfo,20) 
00596     << "ApplySlotFactorCorr " << magbfld << " " << slotscale << endl;
00597 #endif  
00598 
00599   // apply correction
00600   b *= slotscale;
00601 }
00602 
00603 //_____________________________________________________________________________
00604 void BField::ApplyBHFactorCorr(TVector3& b)
00605 {
00606   // 
00607   // Steel chemistry correction (BH)
00608   //
00609   //           Bo                     for Bo > Bcut
00610   //   B'  =   Bo [ 1 + G*(1-Bo/C) ]  for Bcut/3 < Bo < Bcut
00611   //           Bo [ 1 + 2/3*G*Bo/C ]  for Bo < Bcut/3
00612   //
00613 
00614 #ifdef DEBUG
00615   MAXMSG("Bfld",Msg::kInfo,20) 
00616     << "ApplyBHFactorCorr " 
00617     << " BHFactor " << fCurrentPlaneMap->GetBHFactor()
00618     << " BHCutoff " << fCurrentPlaneMap->GetBHCutoff()
00619     << " mag " << b.Mag()
00620     << endl;
00621 #endif
00622 
00623   Double_t bhfactor = fCurrentPlaneMap->GetBHFactor();
00624   if ( bhfactor == 0 ) return;
00625 
00626   Double_t bhcutoff = fCurrentPlaneMap->GetBHCutoff();
00627   if ( bhcutoff == 0 ) return;
00628 
00629   Double_t magbfld  = b.Mag();
00630   if ( magbfld > bhcutoff) return;
00631 
00632   Double_t bhscale = 1.0;
00633   if ( magbfld > bhcutoff/3.0 ) {
00634     bhscale = 1.0 + bhfactor * ( 1.0 - magbfld/bhcutoff );
00635   }
00636   else {
00637     bhscale = 1.0 + (2.0/3.0)*bhfactor*magbfld/bhcutoff;
00638   }
00639 
00640 #ifdef DEBUG
00641   MAXMSG("Bfld",Msg::kInfo,20) 
00642     << "ApplyBhFactorCorr " << bhscale << endl;
00643 #endif 
00644 
00645   // apply correction
00646   b *= bhscale;
00647 }
00648 
00649 //_____________________________________________________________________________
00650 void BField::ApplyBHCurveCorr(TVector3& /* b */ )
00651 {
00652   // Use B-H curve correction
00653   MAXMSG("Bfld",Msg::kWarning,20)
00654     << "BField::ApplyBHCurveCorr not yet implemented!"
00655     << endl;
00656   // do nothing!
00657 }
00658 
00659 //_____________________________________________________________________________
00660 TVector3 BField::BFromLineSource(TVector3& posRelCoil, Double_t current)
00661 {
00662   // Field in air from a line source along z axis
00663 
00664   static double lastcurrent = 9999;
00665   if (lastcurrent != current) {
00666     MAXMSG("Bfld",Msg::kInfo,5)
00667       << "BFromLineSource current is " << current << endl;
00668     lastcurrent = current;
00669   }
00670 
00671   // B = u0*I/2pi*r = 0.003/r
00672   const Double_t u0by2pi = 12.566370614e-7 / (2.0 * TMath::Pi());
00673   
00674   Double_t r = posRelCoil.Perp();
00675   Double_t brbyr = ( u0by2pi * current / r )/r;
00676   Double_t bx    =  posRelCoil.Y() * brbyr;
00677   Double_t by    = -posRelCoil.X() * brbyr;
00678   return TVector3(bx,by,0.0);
00679 
00680 }
00681 
00682 //_____________________________________________________________________________
00683 TVector3 BField::SMGapAndEndFieldNear(const TVector3& position,
00684                                       Ugli::SMRegion_t iregion)
00685 {
00686   // Return the field in the region up-/down- stream of detector
00687   // don't forget to check fIsUVZ
00688 
00689   int w=9, p=4; // 1mm precision
00690   int prec = cout.precision(); // hopefully this is the right output stream 
00691   MAXMSG("Bfld",Msg::kWarning,20)
00692     << "BField::SMGapAndEndFieldNear "
00693     << endl
00694     << "not yet implemented for SMRegion " << Ugli::AsString(iregion) << " @ "
00695     << "[" << setw(w)   << setprecision(p) << position.x()
00696     << "," << setw(w)   << setprecision(p) << position.y()
00697     << "," << setw(w+1) << setprecision(p) << position.z()
00698     << "]"
00699     << resetiosflags(ios::floatfield)  // reset to "%g" format
00700     << setprecision(prec)              // restore precision
00701     << endl;
00702   return zeroBfld;
00703 
00704 }
00705 
00706 //_____________________________________________________________________________
00707 TVector3 BField::SMGapAndEndFieldFar(const TVector3& position,
00708                                      Ugli::SMRegion_t iregion)
00709 {
00710   // Return the field in the region up-/down- stream of detector
00711   // or in the gap between the supermodules
00712   // don't forget to check fIsUVZ
00713 
00714   int w=9, p=4; // 1mm precision
00715   int prec = cout.precision(); // hopefully this is the right output stream 
00716   MAXMSG("Bfld",Msg::kWarning,20)
00717     << "BField::SMGapAndEndFieldFar "
00718     << endl
00719     << "not yet implemented for SMRegion " << Ugli::AsString(iregion) << " @ "
00720     << "[" << setw(w)   << setprecision(p) << position.x()
00721     << "," << setw(w)   << setprecision(p) << position.y()
00722     << "," << setw(w+1) << setprecision(p) << position.z()
00723     << "]"
00724     << resetiosflags(ios::floatfield)  // reset to "%g" format
00725     << setprecision(prec)              // restore precision
00726     << endl;
00727   return zeroBfld;
00728 
00729 }
00730 
00731 //_____________________________________________________________________________
00732 
00733 Int_t BField::GetDoLocalTransform() const
00734 {  return fCache->GetDoLocalTransform(); }
00735 
00736 Int_t BField::GetRequireInZTest() const
00737 {  return fCache->GetRequireInZTest(); }
00738 
00739 Double_t BField::GetZTolerance() const
00740 { return fCache->GetZTolerance(); }
00741 
00742 void BField::SetDoLocalTransform(Int_t iflg)
00743 { 
00744   // Just pass along the value
00745   // NOTE: this can affect other BField objects that share the same cache!
00746   fCache->SetDoLocalTransform(iflg); 
00747 } 
00748 
00749 void BField::SetRequireInZTest(Int_t ival)
00750 { 
00751   // Just pass along the value
00752   // NOTE: this can affect other BField objects that share the same cache!
00753   fCache->SetRequireInZTest(ival); 
00754 } 
00755 
00756 void  BField::SetZTolerance(Double_t zeps)
00757 {
00758   // Just pass along the value
00759   // NOTE: this can affect other BField objects that share the same cache!
00760   fCache->SetZTolerance(zeps);
00761 }
00762 
00763 
00764 //_____________________________________________________________________________
00765 void BField::Print(Option_t * /* option */) const
00766 {
00767    // output info about this BField object
00768 
00769    MSG("Bfld",Msg::kInfo) 
00770      << "BField: created from VldContext " << fVldContext
00771      << endl << " VldRange: " << fVldRange << endl;
00772    MSG("Bfld",Msg::kInfo)
00773      << " Co-ords: " << (fPositionIsUVZ?"UVZ":"XYZ")
00774      << ", NoField: " << (fNoField?"yes":"no")
00775      << endl
00776      << " Power: " << (fPowerOff?"off":"on")
00777      << ", Degaussed: " << (fDegaussed?"yes":"no")
00778      << ", Current: " << fCoilCurrent
00779      << endl
00780      << " UseDCSCoilDir: " << fUseDCSCoilDir
00781      << ", InterPlaneField: " << fDoInterPlaneField
00782      << ", SMGapAndEndField: " << fDoSMGapAndEndField
00783      << ", ApplyBdotScale: " << (fApplyBdotScale?"yes":"no")
00784      << endl
00785      << " BHCorr: " << fDoBHCorrection
00786      << ", SlotCorr: " << fDoSlotCorrection
00787      << endl;
00788    if (fGrid) 
00789      MSG("Bfld",Msg::kInfo) 
00790        << " Grid: " << BfldGrid::AsString(fGrid) << endl;
00791    if (fCache)   {
00792      MSG("Bfld",Msg::kInfo) << " BfldCache: ";
00793      fCache->Print();
00794    }
00795    if (fHandler) {
00796      MSG("Bfld",Msg::kInfo) << " Handler: ";
00797      fHandler->Print();
00798    }
00799 }
00800 
00801 //_____________________________________________________________________________

Generated on Fri Mar 28 15:28:36 2008 for loon by  doxygen 1.3.9.1