AlignChamW0.cxx

Go to the documentation of this file.
00001 ///////////////////////////////////////////////////////////////////////
00002 // $Id: AlignChamW0.cxx,v 1.7 2007/07/05 21:55:40 jpaley Exp $
00003 // 
00004 // lebedev@physics.harvard.edu
00005 ////////////////////////////////////////////////////////////////////////
00006 
00007 #include "Alignment/AlignChamW0.h"
00008 
00009 #include "Bfield/BFMagnet.h"
00010 #include "Bfield/bfield.h"
00011 #include "Config/CfgConfig.h"
00012 #include "Config/CfgParam.h"
00013 #include "EventDataModel/EDMEventHandle.h"
00014 #include "EventDataModel/EDMDataBucket.h"
00015 #include "EventDataModel/EDMEventHeader.h"
00016 #include "Geometry/GTargetGeo.h"
00017 #include "NumericalMethods/NMFit.h"
00018 #include "RunInfo/RIRunConfig.h"
00019 #include "TrkRBase/TrkCand.h"
00020 #include "TrkRBase/WireCross.h"
00021 #include "TrkRBase/WireClust.h"
00022 #include "TrkRBase/TrkRUtil.h"
00023 #include "TrkRBase/TrkChamGeo.h"
00024 
00025 #include <TH1F.h>
00026 #include <TH2F.h>
00027 #include <TTree.h>
00028 #include <TF1.h>
00029 #include <TDirectory.h>
00030 
00031 #include <iostream>
00032 #include <cassert>
00033 #include <cmath>
00034 
00035 MODULE_DECL(AlignChamW0);
00036 ClassImp(AlResidNt);
00037 
00038 using namespace std;
00039 using namespace TrkRUtil;
00040 
00041 //----------------------------------------------------------------------
00042 
00043 int AlignChamW0::fsCham = 0;
00044 
00045 //----------------------------------------------------------------------
00046 
00047 AlignChamW0::AlignChamW0(const char* version) :
00048   JobCModule("AlignChamW0"),
00049   fFolder("")
00050 {
00051   this->SetCfgVersion(version);
00052   CheckInit();
00053 }
00054 
00055 //----------------------------------------------------------------------
00056 
00057 AlignChamW0::~AlignChamW0()
00058 {
00059   fTrackList.clear();
00060 }
00061 
00062 //----------------------------------------------------------------------
00063 
00064 JobCResult AlignChamW0::Ana(const EDMEventHandle& evt)
00065 {
00066   vector<const TrkCand*> vec(0);
00067 
00068   try { evt.Reco().Get(fFolder.c_str(), vec); }
00069   catch (...) { return kFailed; }
00070 
00071   TrkInfo_t ti;
00072 
00073   for (unsigned int i = 0; i < vec.size(); ++i) {
00074     const TrkCand* trk = vec[i];
00075 
00076     if (fFieldOn && 
00077     (fabs(trk->QoverP()) < fMaxMom || fabs(trk->QoverP()) > fMinMom)) {
00078       continue;
00079     }
00080     memset(&ti, 0, sizeof(TrkInfo_t));
00081     
00082     int nClu = 0;
00083     bool haveBC = false;
00084     for (int j = 0; j < trk->NClust(); ++j) {
00085       const WireClust* wc = trk->Clust(j);
00086       if (wc->NWire() > 1) continue;
00087 
00088       int cham = wc->Chamber();
00089       int pl = wc->Plane() - 1;
00090 
00091       if (cham > kBC3) nClu++;
00092       else {
00093     if (!fUseBC) continue;
00094     haveBC = true;
00095       }
00096 
00097       fNClust[cham][pl]++;
00098       
00099       ti.fWire[cham][pl] = wc->AvgWire();
00100       ti.fWeight[cham][pl] = 1.0 / (wc->USig() * wc->USig());
00101     }
00102     if (nClu < fMinNClust) continue;
00103 
00104     ti.fPoQ = trk->PQ();
00105     ti.fChi2 = trk->Chi2() / trk->NDF();
00106     fTrackList.push_back(ti);
00107     if (haveBC) fNTrackWithBC++;
00108   }
00109   return kPassed;
00110 }
00111 
00112 //----------------------------------------------------------------------
00113   
00114 void AlignChamW0::NewRun(int run, int subrun)
00115 {
00116   fNTrackWithBC = 0;
00117   fTrackList.clear();
00118   for (int i = 0; i < kNCham; ++i) {
00119     for (int j = 0; j < kNPlane; ++j) fNClust[i][j] = 0;
00120   }
00121   GMIPPGeo::Instance(run);
00122   if (fLoadAlignment) TrkChamGeo::Instance().Init(run);  
00123   config_bfield(run, subrun);
00124   if (BFMagnet::JGG().ByAtCenter() > 0.5 && 
00125       BFMagnet::Rosie().ByAtCenter() < -0.5) {
00126     fFieldOn = true;
00127   }
00128   else fFieldOn = false;
00129 
00130 }
00131 
00132 //----------------------------------------------------------------------
00133 
00134 void AlignChamW0::EndRun(int run, int /*subrun*/)
00135 {
00136   if ((int) fTrackList.size() < fMinTracks) {
00137     cout << "Don't have enough tracks (" << fTrackList.size() << ") "
00138      << " to do chamber alignment" << endl;
00139     return;
00140   }
00141 
00142   // Choose z0 to be just upstream of DC1, since a lot of tracks
00143   // will only have chambers 1-6, w/o BC's
00144   fZ0 = GMIPPGeo::Instance(run).Target().CenterPos()[2];
00145   TrkCand::Init(fZ0);
00146 
00147   double saveBy = BFMagnet::JGG().ByAtCenter();
00148   
00149   // First align w/o shifting BC positions, then allow to change 
00150   // BC positions
00151   if (!RoughAlign(false)) {
00152     cout << "AlignChamW0: alignment failed" << endl;
00153     return;
00154   }
00155 
00156   TrkChamGeo& db = TrkChamGeo::Instance();
00157   db.SetRunRange(run, run);
00158 
00159   // Save alignment constants with BC's fixed
00160   for (int c = kBC1; c < kNCham; ++c) db.SetCham(c);
00161   db.WriteToDB(TrkChamGeo::kBCFixed, 0770);
00162 
00163   // The other steps (adjusting JGG field scale and BC alignment)
00164   // are only possible if we have enough BC tracks
00165   if (fNTrackWithBC >= fMinTracksBC) {
00166     if (fAdjustBField  && fabs(saveBy) > 0.5) {
00167       // Find the new minimum for B-field, and if the field was changed,
00168       // then we make sure not to finish the loop
00169       AdjustBField();
00170       
00171       if (!RoughAlign(false)) {
00172     cout << "AlignChamW0: alignment failed after JGG scale was changed"
00173          << endl;
00174     return;
00175       }
00176       
00177       cout << "AlignChamW0 run " << run << " beam: " 
00178        << RIRunConfig::Instance(run).Momentum() << " By=" << saveBy
00179        << " now " << BFMagnet::JGG().ByAtCenter()
00180        << " ratio=" << BFMagnet::JGG().ByAtCenter() / saveBy
00181        << endl;
00182       
00183       // Save alignment constants having tweaked JGG field
00184       for (int c = kBC1; c < kNCham; ++c) db.SetCham(c);
00185       db.WriteToDB(TrkChamGeo::kPostJGGScale, 0770);
00186     }
00187     
00188     if (fUseBC) {
00189       if (!RoughAlign(true)) {
00190     cout << "AlignChamW0: couldn't do alignment with BC's" << endl;
00191       }
00192       else {
00193     for (int c = kBC1; c < kNCham; ++c) db.SetCham(c);
00194     db.WriteToDB(TrkChamGeo::kAllCham, 0777);
00195       }      
00196     }
00197   }
00198   else cout << "Number of tracks with BC: " << fNTrackWithBC << "/"
00199         << fMinTracksBC << endl;
00200 
00201 
00202   AnaResid(0);
00203 
00204 }
00205 
00206 //----------------------------------------------------------------------
00207 
00208 void AlignChamW0::Update(const CfgConfig& c)
00209 {
00210   c("LoadAlignment").Get(fLoadAlignment);
00211   c("MaxAlignAttempt").Get(fMaxAlignAttempt);
00212   c("MinNClust").Get(fMinNClust);
00213   c("UseBC").Get(fUseBC);
00214   c("Folder").Get(fFolder);
00215   c("OkShift").Get(fOkShift);
00216   c("MinTracks").Get(fMinTracks);
00217   c("MinTracksBC").Get(fMinTracksBC);
00218   c("AdjustBField").Get(fAdjustBField);
00219   c("MinMom").Get(fMinMom);
00220   c("MaxMom").Get(fMaxMom);
00221 
00222   assert(fMinMom > 0);
00223   assert(fMaxMom > 0);
00224   fMinMom = 1 / fMinMom;
00225   fMaxMom = 1 / fMaxMom;
00226 
00227   fIsInit = true;
00228 }
00229 
00230 //----------------------------------------------------------------------
00231 
00232 double AlignChamW0::Fit(AlignChamW0::TrkInfo_t& trk, 
00233              float* poq /* = 0*/)
00234 {
00235   int nClust = 0;
00236   double u[kNCham * kNPlane];
00237   double w[kNCham * kNPlane];
00238   double z[kNCham * kNPlane];
00239   double cosA[kNCham * kNPlane];
00240   double sinA[kNCham * kNPlane];
00241   double lambdaX[kNCham * kNPlane];
00242   double lambdaY[kNCham * kNPlane];
00243   short chamber[kNCham * kNPlane];
00244 
00245   for (int cham = 0; cham < kNCham; ++cham) {
00246     GChamGeo& geo = GMIPPGeo::Instance().Cham(cham);
00247     for (int p = 0; p < kNPlane; ++p) {
00248       if (trk.fWeight[cham][p] < 1e-3) continue;
00249       geo.WireToU(p + 1, trk.fWire[cham][p], u[nClust]);
00250       w[nClust] = trk.fWeight[cham][p];
00251       z[nClust] = geo.Z(p + 1);
00252       cosA[nClust] = geo.GAngleCos(p + 1);
00253       sinA[nClust] = geo.GAngleSin(p + 1);
00254       lambdaX[nClust] = TrkCand::LambdaX(cham, p);
00255       lambdaY[nClust] = TrkCand::LambdaY(cham, p);
00256       chamber[nClust] = cham * kNPlane + p;
00257       nClust++;
00258     }
00259   }
00260 
00261   double par[5];
00262 
00263   // Make first-pass fit
00264   FitCurvedTrack(nClust, u, w, z, cosA, sinA, fZ0, lambdaX, lambdaY,
00265          par, 0);
00266 
00267   // Initialize lambda's based on the fit
00268   double lamX[kNCham][kNPlane], lamY[kNCham][kNPlane];
00269   CalcLambda(fZ0, lamX, lamY, par, chamber[0] / 4, chamber[nClust - 1] / 4);
00270 
00271   // Adjust lambda for each point based on the rough track parameters
00272   for (int i = 0; i < nClust; ++i) {
00273     lambdaX[i] = lamX[chamber[i] / kNPlane][chamber[i] % kNPlane];;
00274     lambdaY[i] = lamY[chamber[i] / kNPlane][chamber[i] % kNPlane];
00275   }
00276 
00277   // Return chi squared of the fit using better-evaluated lambda's
00278   double chi2 = FitCurvedTrack(nClust, u, w, z, cosA, sinA,
00279                    fZ0, lambdaX, lambdaY, par, 0);
00280   if (!poq) return chi2;
00281   
00282   chi2 /= (double) (nClust - 5);
00283   if (fabs(par[4]) > 1e-3) *poq = 1.0 / par[4];
00284   else *poq = 1e3;
00285 
00286   return chi2;
00287 }
00288 
00289 //----------------------------------------------------------------------
00290 
00291 void AlignChamW0::AnaResid(int i)
00292 {
00293   char name[32];
00294   sprintf(name, "resid%d", i);
00295   TTree* tree = new TTree(name, "Chamber Track Residual Tree");
00296   AlResidNt* nt = new AlResidNt;
00297   tree->Branch("fNt", "AlResidNt", &nt);
00298 
00299   for (unsigned int i = 0; i < fTrackList.size(); ++i) {
00300     Fit(fTrackList[i], nt);
00301     tree->Fill();
00302   }
00303 
00304   tree->Write();
00305   delete tree;
00306   delete nt;
00307 }
00308 
00309 //----------------------------------------------------------------------
00310 
00311 void AlignChamW0::Fit(AlignChamW0::TrkInfo_t& trk, AlResidNt* nt,
00312                int minCham /* = 0 */)
00313 {
00314   double u[kNCham * kNPlane];
00315   double w[kNCham * kNPlane];
00316   double z[kNCham * kNPlane];
00317   double cosA[kNCham * kNPlane];
00318   double sinA[kNCham * kNPlane];
00319   double lambdaX[kNCham * kNPlane];
00320   double lambdaY[kNCham * kNPlane];
00321   short chamber[kNCham * kNPlane];
00322 
00323   nt->nclust = 0;
00324 
00325   for (int cham = minCham; cham < kNCham; ++cham) {
00326     GChamGeo& geo = GMIPPGeo::Instance().Cham(cham);
00327     for (int p = 0; p < kNPlane; ++p) {
00328       if (trk.fWeight[cham][p] < 1e-3) {
00329     nt->u[cham][p] = 1e6;
00330       }
00331       else {
00332     geo.WireToU(p + 1, trk.fWire[cham][p], u[nt->nclust]);
00333     nt->u[cham][p] = u[nt->nclust];
00334     w[nt->nclust] = trk.fWeight[cham][p];
00335     z[nt->nclust] = geo.Z(p + 1);
00336     cosA[nt->nclust] = geo.GAngleCos(p + 1);
00337     sinA[nt->nclust] = geo.GAngleSin(p + 1);
00338     lambdaX[nt->nclust] = TrkCand::LambdaX(cham, p);
00339     lambdaY[nt->nclust] = TrkCand::LambdaY(cham, p);
00340     chamber[nt->nclust] = cham * kNPlane + p;
00341     nt->nclust++;
00342       }
00343     }
00344   }
00345    
00346   double par[5];
00347   
00348   // Make first-pass fit
00349   FitCurvedTrack(nt->nclust, u, w, z, cosA, sinA, 
00350          fZ0, lambdaX, lambdaY, par, 0);
00351   
00352   // Initialize lambda's based on the fit
00353   double lamX[kNCham][kNPlane], lamY[kNCham][kNPlane]; 
00354   CalcLambda(fZ0, lamX, lamY, par, 0, kPWC6);
00355   
00356   // Adjust lambda for each point based on the rough track parameters
00357   for (int i = 0; i < nt->nclust; ++i) {
00358     lambdaX[i] = lamX[chamber[i] / kNPlane][chamber[i] % kNPlane];
00359     lambdaY[i] = lamY[chamber[i] / kNPlane][chamber[i] % kNPlane];
00360   }
00361   
00362   // Return chi squared of the fit using better-evaluated lambda's
00363   nt->chi2 = FitCurvedTrack(nt->nclust, u, w, z, cosA, sinA,
00364                 fZ0, lambdaX, lambdaY, par, 0);
00365   
00366   nt->poq = (fabs(par[4]) > 1e-3) ? (1 / par[4]) : 1e3;
00367   
00368   double x, y;
00369   for (int cham = 0; cham < kNCham; ++cham) {
00370     GChamGeo& geo = GMIPPGeo::Instance().Cham(cham);
00371 
00372     for (int p = 0; p < kNPlane; ++p) {
00373       x = par[0] + (geo.Z(p + 1) - fZ0) * par[2] + par[4] * lamX[cham][p];
00374       y = par[1] + (geo.Z(p + 1) - fZ0) * par[3] + par[4] * lamY[cham][p];
00375     
00376       nt->ufit[cham][p] = x * geo.GAngleCos(p + 1) - 
00377     y * geo.GAngleSin(p + 1);
00378       nt->uperp[cham][p] = x * geo.GAngleSin(p + 1) + 
00379     y * geo.GAngleCos(p + 1);
00380     }
00381   }
00382 
00383   for (int c = 0; c < kNCham; ++c) {
00384     for (int p = 0; p < kNPlane; ++p) {
00385       nt->poqrm[c][p] = 1e6;
00386       nt->chi2rm[c][p] = 1e6;
00387       nt->resid[c][p] = 1e6;
00388     }
00389   }
00390   
00391   double wCopy[kNCham * kNPlane];
00392   // Exclude every hit one by one and record residual
00393   for (int i = 0; i < nt->nclust; ++i) {
00394     int cham = chamber[i] / kNPlane;
00395     int p = chamber[i] % kNPlane;
00396     GChamGeo& geo = GMIPPGeo::Instance().Cham(cham);
00397 
00398     memcpy(wCopy, w, sizeof(w));
00399     wCopy[i] = 0;
00400 
00401     nt->chi2rm[cham][p] = FitCurvedTrack(nt->nclust, u, wCopy, z, cosA, sinA,
00402                      fZ0, lambdaX, lambdaY, par, 0);
00403     
00404     nt->poqrm[cham][p] = (fabs(par[4]) > 1e-3) ? (1 / par[4]) : 1e3;
00405 
00406     x = par[0] + (geo.Z(p + 1) - fZ0) * par[2] + par[4] * lamX[cham][p];
00407     y = par[1] + (geo.Z(p + 1) - fZ0) * par[3] + par[4] * lamY[cham][p];
00408     nt->resid[cham][p] = x * geo.GAngleCos(p + 1) - 
00409       y * geo.GAngleSin(p + 1) - u[i];
00410   }
00411 }
00412 
00413 //----------------------------------------------------------------------
00414 /// Loop through beam tracks, and shift individual wire planes around
00415 /// by 1/2 of the average unbiased residual.
00416 ///
00417 bool AlignChamW0::RoughAlign(bool withBC)
00418 {
00419   TH1F* resH[kNCham][kNPlane];
00420   char str[256];
00421   for (int c = 0; c < kNCham; ++c) {
00422     for (int p = 0; p < kNPlane; ++p) {
00423       sprintf(str, "resid%d%d", c, p);
00424       resH[c][p] = new TH1F(str, str, 400, -2, 2); // 1% wire sp. bins
00425       resH[c][p]->SetXTitle("Residual (wire spacing)");
00426     }
00427   }
00428 
00429   AlResidNt nt;
00430   TDirectory* dir = gDirectory;
00431 
00432   for (int at = 0; ; ++at) {
00433     // Fail this run if we can't quickly converge
00434     if (at >= fMaxAlignAttempt) return false;
00435     int ntrkBC = 0;
00436 
00437     cout << "Chamber align attempt " << at << " with "
00438      << fTrackList.size() << " tracks" << endl;
00439     
00440     if (withBC) sprintf(str, "attemptbc%d", at);
00441     else sprintf(str, "attempt%d", at);
00442     gDirectory->mkdir(str);
00443     gDirectory->cd(str);
00444     
00445     for (unsigned int i = 0; i < fTrackList.size(); ++i) {
00446       // Check that BC1 is present
00447       TrkInfo_t& trk = fTrackList[i];
00448       if (trk.fWeight[0][0] > 0 ||
00449       trk.fWeight[0][1] > 0 ||
00450       trk.fWeight[0][2] > 0 ||
00451       trk.fWeight[0][3] > 0) ntrkBC++;
00452       
00453       Fit(trk, &nt);
00454       for (int c = 0; c < kNCham; ++c) {
00455     for (int p = 0; p < kNPlane; ++p) {
00456       if (nt.resid[c][p] > 1e5) continue;
00457       resH[c][p]->Fill(nt.resid[c][p] / GChamGeo::Pitch(c));
00458     }
00459       }
00460     }
00461 
00462     if (withBC && (ntrkBC < fMinTracksBC)) {
00463       cout << "Can't do alignment with " << ntrkBC << " tracks with "
00464        << " BC info" << endl;
00465       return false;
00466     }
00467 
00468     // Now extract means of the histograms
00469     double maxRes = 0;
00470     int maxResP = -1;
00471     double res[kNCham][kNPlane];
00472     for (int c = 0; c < kNCham; ++c) {
00473       GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00474       for (int p = 0; p < kNPlane; ++p) {
00475     if (resH[c][p]->Integral() < 2) {
00476       res[c][p] = 0;
00477       continue;
00478     }
00479     
00480     res[c][p] = resH[c][p]->GetMean(); 
00481     resH[c][p]->Write();
00482     resH[c][p]->Reset();
00483 
00484     if (withBC || c > kBC3) {
00485       if (fabs(res[c][p]) > fabs(maxRes)) {
00486         maxRes = res[c][p];
00487         maxResP = c * kNPlane + p;
00488       }
00489 
00490       // Shift wire plane with the largest residual by a fraction of 
00491       // the residual
00492       geo.SetWireZero(p + 1, geo.WireZero(p + 1) -
00493               geo.WireDir(p + 1) * res[c][p] * 0.3);
00494     }
00495       }
00496     }
00497     dir->cd();
00498 
00499     if (maxResP < 0) {
00500       cout << "Found no non-zero residuals?" << endl;
00501       return false;
00502     }
00503 
00504     cout << "Maximum residual in " << GChamGeo::Name(maxResP / 4)
00505      << " P" << maxResP % 4 + 1 << ": " << maxRes << endl;
00506   
00507     // Preen track list to throw out those
00508     if (fabs(maxRes) < 0.25 && PreenTrackList(res, withBC)) continue;
00509 
00510     if (fabs(maxRes) < fOkShift) break;
00511   }
00512   for (int c = 0; c < kNCham; ++c) {
00513     for (int p = 0; p < kNPlane; ++p) delete resH[c][p];
00514   }
00515   return true;
00516 }
00517 
00518 //----------------------------------------------------------------------
00519 
00520 int AlignChamW0::PreenTrackList(double res[kNCham][kNPlane], bool withBC)
00521 {
00522   vector<TrkInfo_t>::iterator itr(fTrackList.begin());
00523 
00524   AlResidNt nt;
00525   int removed = 0;
00526 
00527   while (itr != fTrackList.end()) {
00528     TrkInfo_t& trk = *itr;
00529     Fit(trk, &nt);
00530     
00531     int c = withBC ? kBC1 : kDC1;
00532     int p;
00533 
00534     for ( ; c < kNCham; ++c) {
00535       for (p = 0; p < kNPlane; ++p) {
00536     if (trk.fWeight[c][p] <= 0) continue;
00537     double r = fabs(nt.resid[c][p] / GChamGeo::Pitch(c) - res[c][p]);
00538     if (r > 1.5 + fabs(res[c][p])) break;
00539       }
00540       if (p != kNPlane) break;
00541     }
00542     if (c != kNCham) {
00543       itr = fTrackList.erase(itr);
00544       removed++;
00545     }
00546     else itr++;
00547   }
00548   return removed;
00549 }
00550 
00551 //----------------------------------------------------------------------
00552 /// Calculates the sum of chi squared for current B-field, 
00553 /// +/-0.5%, and +/-1%. Based on those 5 points, determines the 
00554 /// new best setting for JGG field.
00555 /// Returns true if the field was changed by more than 0.25%
00556 ///
00557 bool AlignChamW0::AdjustBField()
00558 {
00559   double bNom[5];
00560   bNom[2] = BFMagnet::JGG().ByAtCenter();
00561   if (bNom[2] < 0.5) return false;
00562 
00563   bNom[0] = bNom[2] * 0.990;
00564   bNom[1] = bNom[2] * 0.995;
00565   bNom[3] = bNom[2] * 1.005;
00566   bNom[4] = bNom[2] * 1.010;
00567 
00568   double sum[5];
00569 
00570   for (int i = 0; i < 5; ++i) {
00571     BFMagnet::JGG().SetByAtCenter(bNom[i]);
00572     TrkCand::Init(fZ0);
00573 
00574     sum[i] = 0;
00575     for (unsigned int j = 0; j < fTrackList.size(); ++j) {
00576       sum[i] += Fit(fTrackList[j]);
00577     }
00578   }
00579 
00580   cout << "Chi^2 sums: ";
00581   for (int i = 0; i < 5; ++i) cout << sum[i] << " ";
00582   cout << endl;
00583 
00584   double par[3];
00585   NMFit::FitPol(2, 5, bNom, sum, 0, par);
00586 
00587   double minPos;
00588   if (par[2] > 0) { // We are guaranteed a minimum
00589     minPos = -par[1] / (2.0 * par[2]);
00590     cout << "Minimum is at " << minPos << endl;
00591     if (minPos < bNom[0]) minPos = bNom[0];
00592     else if (minPos > bNom[4]) minPos = bNom[4];
00593   }
00594   else {
00595     cout << "AlignChamW0::AdjustBField(): "
00596      << "we have a problem parameters are: " 
00597      << par[0] << ", " << par[1] << ", " << par[2] << endl;
00598     double slope = 2 * par[2] * bNom[2] + par[1];
00599     if (slope > 0) minPos = bNom[3];
00600     else minPos = bNom[1];
00601   }
00602 
00603   BFMagnet::JGG().SetByAtCenter(minPos);
00604   return (fabs(minPos / bNom[2] - 1) > 2.5e-3);
00605 }
00606 
00607 ////////////////////////////////////////////////////////////////////////

Generated on Mon Nov 23 08:01:43 2009 for MIPP(E907) by  doxygen 1.4.7