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.39 2009/09/16 16:55:44 rhatcher 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.39 2009/09/16 16:55:44 rhatcher 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    fUseDCSCurrent       = that.fUseDCSCurrent;
00184    fGapLineSrc          = that.fGapLineSrc;
00185    fApplyBdotScale      = that.fApplyBdotScale;
00186 
00187    fUseEverywhere       = that.fUseEverywhere; 
00188    fNoFieldBeyondZ      = that.fNoFieldBeyondZ;
00189 
00190    // attach the same cache as the copy-ee
00191    if ( that.fCache ) {
00192      fCache = that.fCache;
00193      fCache->IncrementRef();
00194    }
00195    else {
00196      // hey! this shouldn't happen
00197      assert(0);
00198    } 
00199 
00200    // translate chosen grid back into coarseness
00201    Int_t coarseness = BfldGrid::GetCoarseness(that.fGrid);
00202 
00203    // set the grid and attach appropriate handler
00204    SetGridHandler(fVldContext.GetDetector(),coarseness);
00205 
00206    fHandler->SetCache(fCache);
00207    fHandler->SetLastPolygAsSeed();
00208 
00209    return *this;
00210 }
00211 
00212 //_____________________________________________________________________________
00213 void BField::ResetVldContext(const VldContext& vldc)
00214 {
00215    // for any given VldContext we *should* look up coil status + current
00216  
00217    fVldContext = vldc;
00218    Detector::Detector_t det = vldc.GetDetector();
00219 
00220    VldTimeStamp start = VldTimeStamp::GetBOT();
00221    VldTimeStamp end   = VldTimeStamp::GetEOT();
00222    fVldRange = VldRange(det,vldc.GetSimFlag(),start,end,"");
00223 
00224    if (!fHandler) SetGridHandler(vldc.GetDetector(),-1);
00225 
00226    if (fCache) fCache->DecrementRef(); // unreference previous cache, if any
00227    
00228    // attach a cache we get from a loan pool
00229    fCache = fLoanPool->GetCache(fVldContext);
00230    fCache->IncrementRef();  // let cache know we have a pointer to it
00231    fVldRange.TrimTo(fCache->GetVldRange());
00232 
00233    fHandler->SetCache(fCache);
00234    fHandler->SetLastPolygAsSeed();
00235 
00236    fNoField   = false;
00237    fPowerOff  = false;
00238    fDegaussed = false;
00239 
00240    // here we determine the coil current and whether the detector
00241    // is degaussed (if I=0).  Do it early as special cases 
00242    // (eg. collar/coil or interplane ) might need it.
00243 
00244    // rwh: for now we just say get ready to multiply by 1.0
00245    switch (fVldContext.GetDetector()) {
00246    // nominal values in Amp-turns
00247    case Detector::kNear: 
00248      fCoilCurrent = 40.0 * 1000.;  // nominal "on" value
00249      if ( fUseDCSCurrent ) {
00250        std::pair<Float_t,Float_t> currents = CoilTools::CoilCurrent(vldc);
00251        fCoilCurrent = 8.0 * TMath::Abs(currents.first); // 8 planks * ~ -4973A
00252      }
00253      break;
00254    case Detector::kFar:
00255      fCoilCurrent = 15.2 * 1000.;  // nominal "on" value
00256      if ( fUseDCSCurrent ) {
00257        std::pair<Float_t,Float_t> currents = CoilTools::CoilCurrent(vldc);
00258        Float_t avg_cur = 0.5 * (currents.first+currents.second);
00259        fCoilCurrent = 190 * TMath::Abs(avg_cur); // 190 turns * ~ 80A
00260      }
00261      break;
00262    default:
00263      fCoilCurrent = 0.0;
00264      fNoField = true;
00265    }
00266    // should scale fCoilCurrent by ratio of readback to nominal
00267    // from DCS readback for non-saturated part of field ...
00268 
00269    if (fUseDCSCoilDir == 1 || fUseDCSCoilDir == 2 ) {
00270      if ( ! fUseDCSCurrent && ! CoilTools::IsOK(vldc)) fCoilCurrent = 0.0;
00271      else if (CoilTools::IsReverse(vldc)) fCoilCurrent = -fCoilCurrent;
00272    }
00273 }
00274 
00275 //_____________________________________________________________________________
00276 void BField::Init()
00277 {
00278    // initialize member data
00279    fNoField        = false;
00280    fVldRange       = VldRange();
00281    fGrid           = BfldGrid::kUndefined;
00282    fLastMapVariant = kNoMapUsed;
00283    fUseEverywhere  = 0; 
00284 
00285    // get access to the BfldLoanPool
00286    if (!fLoanPool) fLoanPool = BfldLoanPool::Instance();
00287 
00288    if (fOwnedPlaneMap) { delete fOwnedPlaneMap;  fOwnedPlaneMap = 0; }
00289    fOwnedPlaneMap = new BfldDbiPlaneMap;
00290 }
00291 
00292 //_____________________________________________________________________________
00293 void BField::InitFlagsFromLoanPool()
00294 {
00295    // initialize member data from loan pool
00296 
00297    // get access to the BfldLoanPool
00298    if (!fLoanPool) fLoanPool = BfldLoanPool::Instance();
00299 
00300    fDoBHCorrection      = fLoanPool->GetDefaultDoBHCorrection();
00301    fDoSlotCorrection    = fLoanPool->GetDefaultDoSlotCorrection();
00302    fDoInterPlaneField   = fLoanPool->GetDefaultDoInterPlaneField();
00303    fDoSMGapAndEndField  = fLoanPool->GetDefaultDoSMGapAndEndField();
00304 
00305    fUseDCSCoilDir       = fLoanPool->GetDefaultUseDCSCoilDir();
00306    fUseDCSCurrent       = fLoanPool->GetDefaultUseDCSCurrent();
00307    fGapLineSrc          = fLoanPool->GetDefaultGapLineSrc();
00308    fApplyBdotScale      = fLoanPool->GetDefaultApplyBdotScale();
00309 
00310    fNoFieldBeyondZ      = fLoanPool->GetDefaultNoFieldBeyondZ();
00311 }
00312 
00313 //_____________________________________________________________________________
00314 BField::~BField()
00315 {
00316    // destructor
00317 
00318    if (fHandler)       { delete fHandler;        fHandler = 0; }
00319    // fCache is not owned, can't delete it just change ref count
00320    if (fCache)         { fCache->DecrementRef(); fCache = 0; } 
00321    if (fOwnedPlaneMap) { delete fOwnedPlaneMap;  fOwnedPlaneMap = 0; }
00322 
00323 }
00324 
00325 //_____________________________________________________________________________
00326 void BField::SetInterpMethod(BfldInterpMethod::InterpMethod_t method)
00327 {
00328    // pass on interpolation method message to BFLHandler
00329    if (fHandler) fHandler->SetInterpMethod(method);
00330 }
00331 
00332 //_____________________________________________________________________________
00333 void BField::SetGridHandler(Detector::Detector_t detector, Int_t coarseness)
00334 {
00335    // translate Detector and "coarseness" into Grid enum
00336    fGrid = BfldGrid::GetGrid(detector,coarseness);
00337    
00338    // attach a BfldHandler (delete old if there is one)
00339    if (fHandler) { delete fHandler; fHandler = 0; }
00340 
00341    // check for special case of "rect2d" grid request
00342    if ( BfldGrid::kRect2dGrid == fGrid ) {
00343       // attach a special handler
00344       fHandler = new BfldHandlerRect2d;
00345    } else {
00346       fHandler = new BfldHandlerVoronoi;
00347    }
00348 
00349    // set the default interpolation method
00350    // BField's method simply passes on message to BFLHandler
00351    SetInterpMethod(BfldInterpMethod::kDefault);
00352 
00353    fLastMapVariant = kNoMapUsed;
00354 
00355 }
00356 
00357 //_____________________________________________________________________________
00358 TVector3 BField::GetBField(TVector3& posGlobal, Bool_t isUVZ)
00359 {
00360    // Return the magnetic field for any point in space
00361    // for the currently configured detector
00362    // if isUVZ position is in 
00363 
00364    if (fNoField) return zeroBfld;
00365 
00366    if (posGlobal.Z() > fNoFieldBeyondZ ) return zeroBfld;
00367 
00368    // stash this way for special cases ( coil, SM gap, interplane )
00369    fPositionIsUVZ = isUVZ;
00370    
00371    bool isPosSteelUVZ = isUVZ;
00372    int doLocalTransform = 0;
00373 
00374    if ( fDegaussed && fCoilCurrent == 0 ) return zeroBfld;
00375 
00376    bool was_in_steel = true;
00377 
00378    // calculate which plate (if any) this "z" corresponds to
00379    if (fUseEverywhere) {
00380 
00381      MAXMSG("Bfld",Msg::kWarning,4) 
00382        << "BField::GetBField no coil region handling or " << endl
00383        << "map selection based on plane with useEverywhere=" 
00384        << fUseEverywhere << "."
00385        << endl;
00386      fCurrentPlaneMap = fOwnedPlaneMap;
00387 
00388    } else {
00389 
00390       // check for special cases of geometry (via cache)
00391       //  0 =: don't check, outside steel use either 
00392       //       none (no InterPlaneField) or interplane gap map
00393       // <0 =: check position, but use zero when up/down/gap
00394       // >0 =: check position, try best to model field
00395       if ( fDoSMGapAndEndField ) {
00396         Ugli::SMRegion_t ismregion = fCache->InSMRegion(posGlobal,isUVZ);
00397         if ( ismregion != Ugli::kInSM1 && ismregion != Ugli::kInSM2 ) {
00398           // in SM gap or beyond SM ends
00399           if ( fDoSMGapAndEndField < 0 ) return zeroBfld; // no attempt to model
00400           return SMGapAndEndField(posGlobal,ismregion);
00401         }
00402       }
00403 
00404       // use geometry (via cache) to determine plane
00405       fCurrentPlaneMap = fCache->FindPlaneMap(posGlobal);
00406       was_in_steel = fCache->FindWasInSteel(true);
00407       // check that there was data
00408 
00409       if ( ! fCurrentPlaneMap ) {
00410         // nope?  probably because lacking BfldDbiPlaneMap table
00411         // fake something up to mimic old behaviour
00412         Int_t    imap  = BfldCache::GetDefaultMapVariant(fVldContext);
00413         Double_t scale = BfldCache::GetDefaultScale(fVldContext);
00414         MAXMSG("Bfld",Msg::kWarning,5)
00415           << "GetDefault(MapVariant,Scale) returned (" 
00416           << imap << "," << scale << ")"
00417           << ", called because missing BfldDbiPlaneMap?"
00418           << endl;
00419         fOwnedPlaneMap->SetMapVariant(0,imap);
00420         fOwnedPlaneMap->SetScale(0,scale);   
00421         fCurrentPlaneMap = fOwnedPlaneMap;
00422       }
00423    }
00424 
00425    // by default use the full plane map pair
00426    Int_t indxpair = BfldDbiPlaneMap::kFullSteelA;
00427 
00428    TVector3 posSteel(posGlobal);
00429    doLocalTransform = fCache->GetDoLocalTransform();
00430    if (doLocalTransform > 0) {
00431      posSteel = fCache->GetPositionInSteel();
00432      //if (doLocalTransform > 1) isPosSteelUVZ = false;
00433    }
00434    bool indetail = fCurrentPlaneMap->IsInDetail(posSteel.x(),posSteel.y());
00435 
00436    if ( ! was_in_steel ) {
00437      //
00438      // what to do if not (considered) in the steel
00439      //
00440      // if asked to do nothing ... return zero field
00441      if ( 0 == fDoInterPlaneField ) return zeroBfld;
00442      indxpair = BfldDbiPlaneMap::kDetailGapA;  // default to gap detail map
00443      if ( ! indetail ) {
00444        // not in detail region?
00445        if ( 3 == fDoInterPlaneField ) return zeroBfld;
00446        indxpair = BfldDbiPlaneMap::kFullGapA;
00447        // fall back to line current if no full gap map exists
00448        if (fCurrentPlaneMap->IsPairNull(indxpair) || 
00449            2 == fDoInterPlaneField) {
00450          TVector3 blinesrc(0,0,0);
00451          if ( fGapLineSrc & 1 ) {
00452            TVector3 posCoil = posSteel; // for now!!
00453            blinesrc += BFromLineSource(posCoil,fCoilCurrent);
00454          }
00455          if ( fGapLineSrc & 2 ) {
00456            TVector3 posRelRtnCoil = posGlobal;
00457            // account for position of return coil
00458            switch ( fVldContext.GetDetector() ) {
00459            case Detector::kNear:
00460              posRelRtnCoil -= TVector3(-1.9,-1.9,0);
00461              break;
00462            case Detector::kFar:
00463              posRelRtnCoil -= TVector3( 0.0,-4.8,0);
00464              break;
00465            default:
00466              posRelRtnCoil = TVector3(999.,999.,999.);
00467              break;
00468            }
00469            // note negative sign for fCoilCurrent for return leg
00470            blinesrc += BFromLineSource(posRelRtnCoil,-fCoilCurrent);
00471          }
00472          return blinesrc;
00473        }
00474      }
00475    } else {
00476      //
00477      // what to do if (considered) in the steel
00478      // set the right map pair for the conditions and position
00479      //
00480      if ( fPowerOff ) indxpair = BfldDbiPlaneMap::kPowerOffA;
00481      else if ( indetail ) {
00482        indxpair = BfldDbiPlaneMap::kDetailSteelA;
00483        if (fCurrentPlaneMap->IsPairNull(indxpair)) 
00484          indxpair = BfldDbiPlaneMap::kFullSteelA; // no detail map, revert
00485      }
00486    }
00487 
00488    Bool_t isnull[2];  // check if scale or mapVariant is 0
00489    isnull[0] = fCurrentPlaneMap->IsNull(indxpair);
00490    isnull[1] = fCurrentPlaneMap->IsNull(indxpair+1);
00491 
00492    Double_t coilCurrMap[2] = { 0, 0 };
00493 
00494    if ( isnull[0] && isnull[1] ) return zeroBfld;  // I've got nut'n
00495 
00496    TVector3 bfieldSum(zeroBfld);  // start with zero field
00497 
00498    for (UInt_t iv = 0; iv<2; ++iv) {  // loop over 2 possible contributions
00499 
00500      if ( isnull[iv] ) continue; // no contribution
00501      
00502      // variant refers to (in part) the steel chemistry
00503      // end-plate info to get right "variant"
00504      Int_t mapVariant  = fCurrentPlaneMap->GetMapVariant(indxpair+iv);
00505      Double_t scaleMap = fCurrentPlaneMap->GetScale(indxpair+iv);
00506      // if using DCS for sign, then ignore sign associated with scale
00507      if ( (fUseDCSCoilDir&1) ) scaleMap = TMath::Abs(scaleMap);
00508 
00509      // this should never happen
00510      if (mapVariant == 0) {
00511        MAXMSG("Bfld",Msg::kInfo,5)
00512          << "BField mapVariant=0 indxpair=" << indxpair << " iv=" << iv
00513          << " isnull=" << (isnull[iv]?"true":"false")
00514          << " scaleMap=" << scaleMap
00515          << endl;
00516        MAXMSG("Bfld",Msg::kInfo,5) << *fCurrentPlaneMap << endl;
00517        continue;
00518      }
00519 
00520      BfldMap* bmap = SetupHandlerForMap(mapVariant);
00521  
00522      coilCurrMap[iv] = bmap->GetGeneratedCoilCurrent();
00523      Double_t scaleCoil = fCoilCurrent/coilCurrMap[iv]; 
00524      // probably this effect isn't linear when field is saturated...
00525      Double_t scale = scaleCoil * scaleMap;
00526      //MAXMSG("Bfld",Msg::kDebug,5)
00527      //  << "Bfld scaleCoil " << scaleCoil << " CoilCurrent " << fCoilCurrent
00528      //  << " MapCurrent " << coilCurrMap[iv] << endl;
00529 
00530      // The handler is now configured ... interogate it for the field
00531      bfieldSum += (scale*fHandler->GetBField(posSteel,isPosSteelUVZ));
00532 
00533    } 
00534 
00535    if ( was_in_steel && doLocalTransform > 1 ) {
00536      // get the steel, to tranform B_local to B_global
00537      // note Ugli uses globalInXYZ, while BField uses isUVZ
00538      // always pass true here ... don't double rotate!
00539      UgliSteelPlnHandle usph = fCache->GetCurrentSteelPlnHandle();
00540      bfieldSum = usph.LocalToGlobalVect(bfieldSum,true);
00541    }
00542 
00543    // should these be done by the handler on the pre-(scaled&summed)
00544    // version before summing? i.e. which is more correct:
00545    //  (a)  bhcorr(slotcor(map0))*scale0 + bhcorr(slotcor(map1))*scale1
00546    //  (b)  bhcorr(slotcor(map0*scale0 + map1*scale1))
00547    // this choice is (b) otherwise we should move these to the 
00548    // BfldHandler and make it aware of the flags and initialize
00549    // it with the fCurrentPlaneMap so it can pick up the parameters
00550 
00551    if      ( fDoSlotCorrection   ) ApplySlotFactorCorr(bfieldSum);
00552    if      ( fDoBHCorrection < 0 ) ApplyBHFactorCorr(bfieldSum);
00553    else if ( fDoBHCorrection > 0 ) ApplyBHCurveCorr(bfieldSum);
00554 
00555    if ( fApplyBdotScale ) {
00556      // don't apply to the gap cases
00557      if ( indxpair < BfldDbiPlaneMap::kDetailGapA ) {
00558        Double_t bdot = fCurrentPlaneMap->GetBdotScale();
00559        // don't apply if for some reason bdot value is == 0 (bad DB value)
00560        if (bdot == 0.0) {
00561          MAXMSG("Bfld",Msg::kWarning,5)
00562            << " BdotScale was zero for plane " << fCurrentPlaneMap->GetPlaneId()
00563            << "." << endl;
00564        } else {
00565          bfieldSum *= bdot;
00566        }
00567      }
00568    }
00569 
00570    return bfieldSum;
00571 }
00572                                 
00573 //_____________________________________________________________________________
00574 BfldMap* BField::SetupHandlerForMap(Int_t mapVariant)
00575 {
00576   // Ensure that the BfldHandler is properly configured
00577   // 
00578   if ( fLastMapVariant != mapVariant ) {
00579     //
00580     // map and/or grid has changed ... reinitialize handler
00581     //
00582 
00583     // Get the right base field map
00584     BfldMap  *bmap = fLoanPool->GetMap(fGrid,mapVariant);
00585     fHandler->SetMap(bmap);
00586     
00587     // Get the right Mesh diagram from the LoanPool
00588     // Give our BfldHandler a pointer to the v-diagram
00589     BfldMesh *mesh  = fLoanPool->GetMesh(fGrid,mapVariant);
00590     fHandler->SetMesh(mesh);
00591     
00592     
00593     fLastMapVariant = mapVariant;
00594     
00595   }  // map variant configured
00596   
00597   return fHandler->GetMap();
00598 }
00599 
00600 //_____________________________________________________________________________
00601 void BField::ApplySlotFactorCorr(TVector3& b)
00602 {
00603   //
00604   // Slot (gap) correction formula:
00605   //
00606   //
00607   //   B'  =   Bo                                 for Bo > Bcut
00608   //           Bo [ 1 - D * ( 1 - Bo/Bcut )^2 ]   
00609   //
00610 
00611 #ifdef DEBUG
00612   MAXMSG("Bfld",Msg::kInfo,20) 
00613     << "ApplySlotFactorCorr " 
00614     << " SlotFactor " << fCurrentPlaneMap->GetSlotFactor()
00615     << " SlotCutoff " << fCurrentPlaneMap->GetSlotCutoff()
00616     << " mag " << b.Mag()
00617     << endl;
00618 #endif
00619 
00620   Double_t slotfactor = fCurrentPlaneMap->GetSlotFactor();
00621   if ( slotfactor == 0 ) return;
00622   
00623   Double_t slotcutoff = fCurrentPlaneMap->GetSlotCutoff();
00624   if ( slotcutoff == 0 ) return;
00625      
00626   Double_t magbfld    = b.Mag();
00627   if ( magbfld > slotcutoff ) return;
00628      
00629   Double_t inner = 1.0 - magbfld/slotcutoff;
00630   Double_t slotscale = 1.0 - slotfactor * inner*inner;
00631 
00632 #ifdef DEBUG
00633   MAXMSG("Bfld",Msg::kInfo,20) 
00634     << "ApplySlotFactorCorr " << magbfld << " " << slotscale << endl;
00635 #endif  
00636 
00637   // apply correction
00638   b *= slotscale;
00639 }
00640 
00641 //_____________________________________________________________________________
00642 void BField::ApplyBHFactorCorr(TVector3& b)
00643 {
00644   // 
00645   // Steel chemistry correction (BH)
00646   //
00647   //           Bo                     for Bo > Bcut
00648   //   B'  =   Bo [ 1 + G*(1-Bo/C) ]  for Bcut/3 < Bo < Bcut
00649   //           Bo [ 1 + 2/3*G*Bo/C ]  for Bo < Bcut/3
00650   //
00651 
00652 #ifdef DEBUG
00653   MAXMSG("Bfld",Msg::kInfo,20) 
00654     << "ApplyBHFactorCorr " 
00655     << " BHFactor " << fCurrentPlaneMap->GetBHFactor()
00656     << " BHCutoff " << fCurrentPlaneMap->GetBHCutoff()
00657     << " mag " << b.Mag()
00658     << endl;
00659 #endif
00660 
00661   Double_t bhfactor = fCurrentPlaneMap->GetBHFactor();
00662   if ( bhfactor == 0 ) return;
00663 
00664   Double_t bhcutoff = fCurrentPlaneMap->GetBHCutoff();
00665   if ( bhcutoff == 0 ) return;
00666 
00667   Double_t magbfld  = b.Mag();
00668   if ( magbfld > bhcutoff) return;
00669 
00670   Double_t bhscale = 1.0;
00671   if ( magbfld > bhcutoff/3.0 ) {
00672     bhscale = 1.0 + bhfactor * ( 1.0 - magbfld/bhcutoff );
00673   }
00674   else {
00675     bhscale = 1.0 + (2.0/3.0)*bhfactor*magbfld/bhcutoff;
00676   }
00677 
00678 #ifdef DEBUG
00679   MAXMSG("Bfld",Msg::kInfo,20) 
00680     << "ApplyBhFactorCorr " << bhscale << endl;
00681 #endif 
00682 
00683   // apply correction
00684   b *= bhscale;
00685 }
00686 
00687 //_____________________________________________________________________________
00688 void BField::ApplyBHCurveCorr(TVector3& /* b */ )
00689 {
00690   // Use B-H curve correction
00691   MAXMSG("Bfld",Msg::kWarning,20)
00692     << "BField::ApplyBHCurveCorr not yet implemented!"
00693     << endl;
00694   // do nothing!
00695 }
00696 
00697 //_____________________________________________________________________________
00698 TVector3 BField::BFromLineSource(TVector3& posRelCoil, Double_t current)
00699 {
00700   // Field in air from a line source along z axis
00701 
00702   static double lastcurrent = 9999;
00703   if (lastcurrent != current) {
00704     MAXMSG("Bfld",Msg::kInfo,5)
00705       << "BFromLineSource current is " << current << endl;
00706     lastcurrent = current;
00707   }
00708 
00709   // B = u0*I/2pi*r = 0.003/r
00710   const Double_t u0by2pi = 12.566370614e-7 / (2.0 * TMath::Pi());
00711   
00712   Double_t r = posRelCoil.Perp();
00713   // protect against divide by zero
00714   r = TMath::Max(r,Munits::cm);  // no line src smaller than 1 cm
00715   Double_t brbyr = ( u0by2pi * current / r )/r;
00716   Double_t bx    =  posRelCoil.Y() * brbyr;
00717   Double_t by    = -posRelCoil.X() * brbyr;
00718   return TVector3(bx,by,0.0);
00719 
00720 }
00721 
00722 //_____________________________________________________________________________
00723 TVector3 BField::SMGapAndEndFieldNear(const TVector3& position,
00724                                       Ugli::SMRegion_t iregion)
00725 {
00726   // Return the field in the region up-/down- stream of detector
00727   // don't forget to check fIsUVZ
00728 
00729   int w=9, p=4; // 1mm precision
00730   int prec = cout.precision(); // hopefully this is the right output stream 
00731   MAXMSG("Bfld",Msg::kWarning,20)
00732     << "BField::SMGapAndEndFieldNear "
00733     << endl
00734     << "not yet implemented for SMRegion " << Ugli::AsString(iregion) << " @ "
00735     << "[" << setw(w)   << setprecision(p) << position.x()
00736     << "," << setw(w)   << setprecision(p) << position.y()
00737     << "," << setw(w+1) << setprecision(p) << position.z()
00738     << "]"
00739     << resetiosflags(ios::floatfield)  // reset to "%g" format
00740     << setprecision(prec)              // restore precision
00741     << endl;
00742   return zeroBfld;
00743 
00744 }
00745 
00746 //_____________________________________________________________________________
00747 TVector3 BField::SMGapAndEndFieldFar(const TVector3& position,
00748                                      Ugli::SMRegion_t iregion)
00749 {
00750   // Return the field in the region up-/down- stream of detector
00751   // or in the gap between the supermodules
00752   // don't forget to check fIsUVZ
00753 
00754   int w=9, p=4; // 1mm precision
00755   int prec = cout.precision(); // hopefully this is the right output stream 
00756   MAXMSG("Bfld",Msg::kWarning,20)
00757     << "BField::SMGapAndEndFieldFar "
00758     << endl
00759     << "not yet implemented for SMRegion " << Ugli::AsString(iregion) << " @ "
00760     << "[" << setw(w)   << setprecision(p) << position.x()
00761     << "," << setw(w)   << setprecision(p) << position.y()
00762     << "," << setw(w+1) << setprecision(p) << position.z()
00763     << "]"
00764     << resetiosflags(ios::floatfield)  // reset to "%g" format
00765     << setprecision(prec)              // restore precision
00766     << endl;
00767   return zeroBfld;
00768 
00769 }
00770 
00771 //_____________________________________________________________________________
00772 
00773 Int_t BField::GetDoLocalTransform() const
00774 {  return fCache->GetDoLocalTransform(); }
00775 
00776 Int_t BField::GetRequireInZTest() const
00777 {  return fCache->GetRequireInZTest(); }
00778 
00779 Double_t BField::GetZTolerance() const
00780 { return fCache->GetZTolerance(); }
00781 
00782 void BField::SetDoLocalTransform(Int_t iflg)
00783 { 
00784   // Just pass along the value
00785   // NOTE: this can affect other BField objects that share the same cache!
00786   fCache->SetDoLocalTransform(iflg); 
00787 } 
00788 
00789 void BField::SetRequireInZTest(Int_t ival)
00790 { 
00791   // Just pass along the value
00792   // NOTE: this can affect other BField objects that share the same cache!
00793   fCache->SetRequireInZTest(ival); 
00794 } 
00795 
00796 void  BField::SetZTolerance(Double_t zeps)
00797 {
00798   // Just pass along the value
00799   // NOTE: this can affect other BField objects that share the same cache!
00800   fCache->SetZTolerance(zeps);
00801 }
00802 
00803 
00804 //_____________________________________________________________________________
00805 void BField::Print(Option_t * /* option */) const
00806 {
00807    // output info about this BField object
00808 
00809    MSG("Bfld",Msg::kInfo) 
00810      << "BField: created from VldContext " << fVldContext
00811      << endl << " VldRange: " << fVldRange << endl;
00812    MSG("Bfld",Msg::kInfo)
00813      << " Co-ords: " << (fPositionIsUVZ?"UVZ":"XYZ")
00814      << ", NoField: " << (fNoField?"yes":"no")
00815      << endl
00816      << " Power: " << (fPowerOff?"off":"on")
00817      << ", Degaussed: " << (fDegaussed?"yes":"no")
00818      << ", Current: " << fCoilCurrent
00819      << endl
00820      << " UseDCSCoilDir: " << fUseDCSCoilDir
00821      << ", UseDCSCurrent: " << fUseDCSCurrent
00822      << ", GapLineSrc: " << fGapLineSrc
00823      << ", InterPlaneField: " << fDoInterPlaneField
00824      << ", SMGapAndEndField: " << fDoSMGapAndEndField
00825      << ", ApplyBdotScale: " << (fApplyBdotScale?"yes":"no")
00826      << endl
00827      << " BHCorr: " << fDoBHCorrection
00828      << ", SlotCorr: " << fDoSlotCorrection
00829      << endl;
00830    if (fGrid) 
00831      MSG("Bfld",Msg::kInfo) 
00832        << " Grid: " << BfldGrid::AsString(fGrid) << endl;
00833    if (fCache)   {
00834      MSG("Bfld",Msg::kInfo) << " BfldCache: ";
00835      fCache->Print();
00836    }
00837    if (fHandler) {
00838      MSG("Bfld",Msg::kInfo) << " Handler: ";
00839      fHandler->Print();
00840    }
00841 }
00842 
00843 //_____________________________________________________________________________

Generated on Sat Nov 7 01:25:08 2009 for loon by  doxygen 1.3.9.1