AlignBC.cxx

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////
00002 // $Id: AlignBC.cxx,v 1.3 2007/07/05 21:55:40 jpaley Exp $
00003 // 
00004 // lebedev@physics.harvard.edu
00005 ////////////////////////////////////////////////////////////////////////
00006 
00007 #include "Alignment/AlignBC.h"
00008 
00009 #include "ChamCalib/ChamDrift.h"
00010 #include "Config/CfgConfig.h"
00011 #include "Config/CfgParam.h"
00012 #include "EventDataModel/EDMEventHandle.h"
00013 #include "TrkRBase/TrackSeg.h"
00014 #include "TrkRBase/WireCross.h"
00015 #include "TrkRBase/WireClust.h"
00016 #include "TrkRBase/TrkRUtil.h"
00017 #include "TrkRBase/TrkChamGeo.h"
00018 
00019 #include <TDirectory.h>
00020 #include <TTree.h>
00021 #include <TH1F.h>
00022 #include <TF1.h>
00023 
00024 #include <iostream>
00025 #include <cassert>
00026 #include <cmath>
00027 
00028 MODULE_DECL(AlignBC);
00029 ClassImp(BCAlignNt);
00030 
00031 using namespace std;
00032 using namespace TrkRUtil;
00033 
00034 AlignBC* AlignBC::fsModule = 0;
00035 double AlignBC::fZ1 = 0;
00036 double AlignBC::fZ2 = 0;
00037 
00038 //----------------------------------------------------------------------
00039 
00040 AlignBC::AlignBC(const char* version) :
00041   JobCModule("AlignBC")
00042 {
00043   SetCfgVersion(version);
00044   CheckInit();
00045 }
00046 
00047 //----------------------------------------------------------------------
00048 
00049 JobCResult AlignBC::Ana(const EDMEventHandle& evt)
00050 {
00051   vector<const TrackSeg*> vec(0);
00052   // Make sure raw and calibrated data buckets are loaded
00053   evt.Raw(); 
00054   evt.Cal();
00055   try {evt.Reco().Get(fTrkFolder.c_str(), vec); }
00056   catch (...) {return kFailed;}
00057 
00058   int nTrk = vec.size();
00059   if (nTrk == 0 || nTrk > fMaxNTrackEvt) return kFailed;
00060 
00061   TrkInfo_t *trkInfo = 0;
00062   
00063   // Copy vector info into our private struct
00064   for (int i = 0; i < nTrk; ++i) {
00065     const TrackSeg* seg = vec[i];
00066 
00067     if (!trkInfo) trkInfo = new TrkInfo_t;
00068 
00069     int nGoodClu = seg->NClust();
00070     // Skip tracks with too few clusters
00071     if (nGoodClu < fMinNClust) continue;
00072 
00073     for (int cham = 0; cham < kNBC; ++cham) {
00074       for (int p = 0; p < kNPlane; ++p) {
00075     const WireClust* wc = seg->Clust(cham, p);
00076     if (!wc || wc->NWire() > 1) {
00077       trkInfo->fWeight[cham][p] = -1;
00078       nGoodClu--;
00079       if (nGoodClu < fMinNClust) {
00080         cham = kNBC;
00081         break;
00082       }
00083     }
00084     else {
00085       assert(wc->Plane() == p + 1);
00086       trkInfo->fWire[cham][p] = wc->AvgWire();
00087       trkInfo->fWeight[cham][p] = 1 / (wc->USig() * wc->USig());
00088       trkInfo->fT[cham][p] = wc->T();
00089     }
00090       }
00091     }
00092     if (nGoodClu < fMinNClust) continue;
00093     fTrkInfo.push_back(trkInfo);
00094     trkInfo = 0;
00095   }
00096 
00097   return kPassed;
00098 }
00099 
00100 //----------------------------------------------------------------------
00101 
00102 void AlignBC::NewRun(int /*run*/, int /*subrun*/)
00103 {
00104 }
00105 
00106 //----------------------------------------------------------------------
00107 
00108 void AlignBC::EndRun(int run, int /*subrun*/)
00109 {
00110   if ((int) fTrkInfo.size() < fMinNTrack) {
00111     cout << "AlignBC: " << fTrkInfo.size() << " is not enough tracks"
00112      << endl;
00113     return;
00114   }
00115 
00116   fZ1 = GMIPPGeo::Instance().Cham(kBC1).ZGas();
00117   fZ2 = GMIPPGeo::Instance().Cham(kBC3).ZGas();
00118   
00119   double startPar[kNBC][kNPlane];
00120   for (int c = 0; c < kNBC; ++c) {
00121     GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00122     for (int p = 0; p < kNPlane; ++p) startPar[c][p] = geo.WireZero(p + 1);
00123   }
00124 
00125   if (!RoughAlign()) return;
00126 
00127   for (int c = 0; c < kNBC; ++c) {
00128     GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00129     cout << geo.Name() << " wire 0 changes: ";
00130     for (int p = 0; p < kNPlane; ++p) {
00131       cout << geo.WireZero(p + 1) - startPar[c][p] << " ";
00132     }
00133     cout << endl;
00134   }
00135 
00136   if (fFillNt) FillNt("nt1", false);
00137 
00138   if (fDoFineAlign) {
00139     FineAlign();
00140 
00141     for (int c = 0; c < kNBC; ++c) {
00142       GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00143       cout << geo.Name() << " wire 0 changes: ";
00144       for (int p = 0; p < kNPlane; ++p) {
00145     cout << geo.WireZero(p + 1) - startPar[c][p] << " ";
00146       }
00147       cout << endl;
00148     }
00149 
00150     if (fFillNt) FillNt("nt2", true);
00151   }
00152 
00153   WriteToDB(run);
00154 }
00155 
00156 //----------------------------------------------------------------------
00157 
00158 void AlignBC::FillNt(const char* name, bool resolve)
00159 {
00160   BCAlignNt *nt = new BCAlignNt;
00161   TTree* tree = new TTree(name, "BC Alignment Ntuple");
00162   tree->Branch("nt", "BCAlignNt", &nt);
00163 
00164   double x1[3], x2[3], x3[3];
00165   x1[2] = fZ1;
00166   x2[2] = fZ2;
00167 
00168   for (unsigned int i = 0; i < fTrkInfo.size(); ++i) {
00169     if (!Fit(fTrkInfo[i], nt, resolve)) continue;
00170 
00171     x1[0] = nt->par[0];
00172     x1[1] = nt->par[1];
00173     x2[0] = nt->par[2];
00174     x2[1] = nt->par[3];
00175 
00176     for (int c = 0; c < kNBC; ++c) {
00177       GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00178       for (int p = 0; p < kNPlane; ++p) {
00179     x3[2] = geo.Z(p + 1);
00180     PredictXY(x1, 0, x2, 0, x3, 0);
00181     nt->uperp[c][p] = x3[0] * geo.GAngleSin(p + 1) + 
00182       x3[1] * geo.GAngleCos(p + 1);
00183     nt->ufit[c][p] = x3[0] * geo.GAngleCos(p + 1) -
00184       x3[1] * geo.GAngleSin(p + 1);
00185       }
00186     }
00187     tree->Fill();
00188   }
00189   tree->Write();
00190   delete tree;
00191   delete nt;
00192 }
00193 
00194 //----------------------------------------------------------------------
00195 
00196 void AlignBC::Update(const CfgConfig& c)
00197 {
00198   c("DoFineAlign").Get(fDoFineAlign); 
00199   c("MaxAlignAttempt").Get(fMaxAlignAttempt);
00200   c("MinNClust").Get(fMinNClust);
00201   c("MinNTrack").Get(fMinNTrack);
00202   c("MaxNTrackEvt").Get(fMaxNTrackEvt);
00203   c("TrkFolder").Get(fTrkFolder);
00204   c("OkRoughShift").Get(fOkRoughShift);
00205   c("OkFineShift").Get(fOkFineShift);
00206   c("MinTime").Get(fMinTime);
00207   c("MaxTime").Get(fMaxTime);
00208   c("FillNt").Get(fFillNt);
00209 
00210   fIsInit = true;
00211 }
00212 
00213 //----------------------------------------------------------------------
00214 
00215 bool AlignBC::Fit(const TrkInfo_t* ti, BCAlignNt* nt, 
00216              bool resolve /* = false */)
00217 {
00218   double w[12];
00219   double u[12];
00220   double du[12]; // Shift proportional to drift time
00221   double z[12];
00222   double cosA[12];
00223   double sinA[12];
00224   short  plane[12];
00225 
00226   ChamDrift& drift = ChamDrift::Instance();
00227   
00228   // Copy information from TrkInfo_t into arrays
00229   nt->nclust = 0;
00230   for (int cham = 0; cham < kNBC; ++cham) {
00231     GChamGeo& geo = GMIPPGeo::Instance().Cham(cham);
00232     for (int p = 0; p < kNPlane; ++p) {
00233       if (ti->fWeight[cham][p] <= 0) {
00234     nt->u[cham][p] = 1e6;
00235     continue;
00236       }
00237 
00238       if (resolve) {
00239     if(ti->fT[cham][p] < fMinTime || 
00240        ti->fT[cham][p] > fMaxTime) continue;
00241     du[nt->nclust] = 
00242       drift.TimeToDist(cham, p, ti->fT[cham][p], &w[nt->nclust]);
00243     w[nt->nclust] = 1 / (w[nt->nclust] * w[nt->nclust]);
00244       }
00245       else w[nt->nclust] = ti->fWeight[cham][p];
00246       
00247       geo.WireToU(p + 1, ti->fWire[cham][p], u[nt->nclust]);
00248       nt->u[cham][p] = u[nt->nclust];
00249       z[nt->nclust] = geo.Z(p + 1);
00250       cosA[nt->nclust] = geo.GAngleCos(p + 1);
00251       sinA[nt->nclust] = geo.GAngleSin(p + 1);
00252       plane[nt->nclust] = cham * kNPlane + p;
00253       nt->nclust++;
00254     }
00255   }
00256 
00257   if (nt->nclust < 5) return false;
00258 
00259   // Resolve ambiguity if we need to
00260   double par[4];
00261   if (resolve) {
00262     int bestMask = 0;
00263     nt->chi2 = 1e6;
00264     int nCombo = (1 << nt->nclust);
00265 
00266     double uCopy[12];
00267     for (int m = 0; m < nCombo; ++m) {
00268       bool okCombo = true; 
00269 
00270       for (int i = 0; i < nt->nclust; ++i) {
00271     if (m & (1 << i)) {
00272       // We don't have to double count combinations with du=0
00273       if (du[i] < 1e-6) {
00274         okCombo = false;
00275         break;
00276       }
00277       uCopy[i] = u[i] - du[i];
00278     }
00279     else uCopy[i] = u[i] + du[i];
00280       }
00281       if (!okCombo) continue;
00282 
00283       double c2 = FitLineFromWires(nt->nclust, uCopy, w, z, cosA, sinA, 
00284                    fZ1, fZ2, par, 0);
00285       if (c2 < nt->chi2) {
00286     nt->chi2 = c2;
00287     bestMask = m;
00288       }
00289     }
00290 
00291 //     cout << "Resolved with best mask " << (void*) bestMask
00292 //   << ", chi2 = " << nt->chi2 << "/" << nt->nclust - 4 << endl;
00293     for (int i = 0; i < nt->nclust; ++i) {
00294       if (bestMask & (1 << i)) u[i] -= du[i];
00295       else u[i] += du[i];
00296       nt->u[plane[i] / 4][plane[i] % 4] = u[i];
00297     }
00298   }
00299 
00300   // Save chi squared for the full fit
00301   nt->chi2 = FitLineFromWires(nt->nclust, u, w, z, cosA, sinA, 
00302                   fZ1, fZ2, par, 0);
00303 
00304   for (int i = 0; i < 4; ++i) nt->par[i] = par[i];
00305   nt->z1 = fZ1;
00306   nt->z2 = fZ2;
00307 
00308   double wCopy[12];
00309 
00310   double x1[3], x2[3], x3[3];
00311   x1[2] = fZ1;
00312   x2[2] = fZ2;
00313 
00314   // Now exclude one plane at a time, and save residuals
00315   for (int c = 0; c < kNBC; ++c) {
00316     GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00317     for (int p = 0; p < kNPlane; ++p) {
00318       if (ti->fWeight[c][p] <= 0) {
00319     nt->chi2rm[c][p] = 1e6;
00320     nt->resid[c][p] = 1e6;
00321     continue;
00322       }
00323       
00324       memcpy(wCopy, w, 12 * sizeof(double));
00325       
00326       int i = 0;
00327       for ( ; i < nt->nclust; ++i) {
00328     if (plane[i] == c * kNPlane + p) {
00329       wCopy[i] = 0;
00330       break;
00331     }
00332       }
00333       if (i >= nt->nclust) {
00334     nt->chi2rm[c][p] = 1e6;
00335     nt->resid[c][p] = 1e6;
00336     continue;
00337       }
00338       
00339       nt->chi2rm[c][p] = 
00340     FitLineFromWires(nt->nclust, u, wCopy, z, cosA, sinA, 
00341                fZ1, fZ2, par, 0);
00342       x1[0] = par[0];
00343       x1[1] = par[1];
00344       x2[0] = par[2];
00345       x2[1] = par[3];
00346       x3[2] = geo.Z(p + 1);
00347 
00348       PredictXY(x1, 0, x2, 0, x3, 0);
00349       nt->resid[c][p] = x3[0] * geo.GAngleCos(p + 1) - 
00350     x3[1] * geo.GAngleSin(p + 1) - u[i];
00351     }
00352   }
00353 
00354   return true;
00355 }
00356 
00357 //----------------------------------------------------------------------
00358 
00359 bool AlignBC::RoughAlign()
00360 {
00361   TH1F* resH[kNBC][kNPlane];
00362   
00363   char str[256];
00364   for (int c = 0; c < kNBC; ++c) {
00365     for (int p = 0; p < kNPlane; ++p) {
00366       sprintf(str, "resid%d%d", c, p);
00367       resH[c][p] = new TH1F(str, str, 400, -2, 2); // 1% wire spacing bins
00368       resH[c][p]->SetXTitle("Residual (wire spacing)");
00369     }
00370   }
00371 
00372   BCAlignNt nt;
00373   TDirectory* dir = gDirectory;
00374 
00375   for (int at = 0; ; ++at) {
00376     if (at >= fMaxAlignAttempt) return false;
00377     cout << "BC align attempt " << at << " with " << fTrkInfo.size()
00378      << " tracks" << endl;
00379     sprintf(str, "attempt%d", at);
00380     gDirectory->mkdir(str);
00381     gDirectory->cd(str);
00382 
00383     for (unsigned int i = 0; i < fTrkInfo.size(); ++i) {
00384       if (!Fit(fTrkInfo[i], &nt)) continue;
00385       for (int c = 0; c < kNBC; ++c) {
00386     for (int p = 0; p < kNPlane; ++p) { 
00387       if (nt.resid[c][p] > 100) continue;
00388       resH[c][p]->Fill(nt.resid[c][p] / GChamGeo::Pitch(c));
00389     }
00390       }
00391     }
00392 
00393     double res[3][4];
00394     double maxRes = 0;
00395     int maxResP = -1;
00396     for (int c = 0; c < kNBC; ++c) {
00397       GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00398       for (int p = 0; p < kNPlane; ++p) {
00399     if (resH[c][p]->GetEntries() > 50) {
00400       res[c][p] = resH[c][p]->GetMean();
00401       if (fabs(maxRes) < fabs(res[c][p])) {
00402         maxRes = res[c][p];
00403         maxResP = c * kNPlane + p;
00404       }
00405     }
00406     resH[c][p]->Write();
00407     resH[c][p]->Reset();
00408 
00409     // Shift wire plane by a fraction of residual
00410     geo.SetWireZero(p + 1, geo.WireZero(p + 1) -
00411             geo.WireDir(p + 1) * res[c][p] * 0.3);
00412 
00413       }
00414     }
00415 
00416     dir->cd();
00417 
00418     if (maxResP < 0) return false;
00419 
00420     cout << "Max residual in " << GChamGeo::Name(maxResP / 4) 
00421      << " P" << maxResP % 4 + 1 << ": " << maxRes << " w.s." << endl;
00422     if (fabs(maxRes) < 0.25 && PreenTrackList(res)) continue;
00423     if (fabs(maxRes) < fOkRoughShift) break;
00424   }
00425 
00426   for (int c = 0; c < kNBC; ++c) {
00427     for (int p = 0; p < kNPlane; ++p) delete resH[c][p];
00428   }
00429   return true;
00430 }
00431 
00432 //----------------------------------------------------------------------
00433 
00434 bool AlignBC::PreenTrackList(double res[3][4])
00435 {
00436   int removed = 0;
00437   BCAlignNt nt;
00438   int c, p;
00439 
00440   vector<TrkInfo_t*>::iterator itr(fTrkInfo.begin());
00441   int n = fTrkInfo.size();
00442   for ( ; itr != fTrkInfo.end(); ) {
00443     const TrkInfo_t* ti = *itr;
00444     n--;
00445     if (!Fit(ti, &nt)) {
00446       delete ti;
00447       itr = fTrkInfo.erase(itr);
00448       removed++;
00449       continue;
00450     }
00451 
00452     for (c = 0; c < 3; ++c) {
00453       for (p = 0; p < 4; ++p) {
00454     double r = fabs(nt.resid[c][p] / GChamGeo::Pitch(c) - res[c][p]) ;
00455     if (r < 1e3 && r > 1.5 + fabs(res[c][p]))
00456       break;
00457       }
00458       if (p != 4) break;
00459     }
00460 
00461     if (c != 3) {
00462       delete ti;
00463       itr = fTrkInfo.erase(itr);
00464       removed++;
00465     }
00466     else ++itr;
00467   }
00468 
00469   return (removed != 0);
00470 }
00471 
00472 //----------------------------------------------------------------------
00473 
00474 bool AlignBC::FineAlign()
00475 {
00476 
00477   TH1F* resH[kNBC][kNPlane];
00478   
00479   char str[256];
00480   for (int c = 0; c < kNBC; ++c) {
00481     for (int p = 0; p < kNPlane; ++p) {
00482       sprintf(str, "resid%d%d", c, p);
00483       resH[c][p] = new TH1F(str, str, 240, -0.3, 0.3); // 25 micron bins
00484       resH[c][p]->SetXTitle("Residual (cm)");
00485     }
00486   }
00487 
00488   TF1* fu = new TF1("fu", "gaus", -1, 1);
00489 
00490   BCAlignNt nt;
00491   TDirectory* dir = gDirectory;
00492 
00493   for (int at = 0; ; ++at) {
00494     cout << "BC Fine align attempt " << at << endl;
00495     sprintf(str, "fine%d", at);
00496     gDirectory->mkdir(str);
00497     gDirectory->cd(str);
00498 
00499     double maxShift = 0;
00500 
00501     int nTrk = 0;
00502     for (unsigned int i = 0; i < fTrkInfo.size(); ++i) {
00503       if (!Fit(fTrkInfo[i], &nt, true)) continue;
00504       nTrk++;
00505       for (int c = 0; c < kNBC; ++c) {
00506     for (int p = 0; p < kNPlane; ++p) { 
00507       if (fabs(nt.resid[c][p]) > 0.3) continue;
00508       resH[c][p]->Fill(nt.resid[c][p]);
00509     }
00510       }
00511     }
00512 
00513     if (nTrk < 100) return false;
00514 
00515     for (int c = 0; c < kNBC; ++c) {
00516       GChamGeo& geo = GMIPPGeo::Instance().Cham(c);
00517       for (int p = 0; p < kNPlane; ++p) {
00518     if (resH[c][p]->GetEntries() > 50) {
00519       fu->SetParameter(0, resH[c][p]->GetMaximum());
00520       fu->SetParLimits(0, resH[c][p]->GetMaximum() * 0.7,
00521                resH[c][p]->GetMaximum() * 1.5);
00522       fu->SetParameter(1, resH[c][p]->GetMean());
00523       fu->SetParLimits(1, resH[c][p]->GetMean() - 0.2, 
00524                resH[c][p]->GetMean() + 0.2);
00525       fu->SetParameter(2, resH[c][p]->GetRMS());
00526       resH[c][p]->Fit(fu, "Q0+");
00527 
00528       double res = fu->GetParameter(1);
00529       res *= 0.3 / geo.Pitch();
00530       if (maxShift < fabs(res)) maxShift = fabs(res);
00531       
00532       geo.SetWireZero(p + 1, geo.WireZero(p + 1) + res);
00533     }
00534     resH[c][p]->Write();
00535     resH[c][p]->Reset();
00536       }
00537     }
00538 
00539     dir->cd();
00540     cout << "Max shift: " << maxShift << endl;
00541     if (maxShift < fOkFineShift) break;
00542   }
00543 
00544   for (int c = 0; c < kNBC; ++c) {
00545     for (int p = 0; p < kNPlane; ++p) delete resH[c][p];
00546   }
00547   delete fu;
00548 
00549   return true;
00550 }
00551 
00552 //----------------------------------------------------------------------
00553 
00554 void AlignBC::WriteToDB(int run)
00555 {
00556   static int minRun = 10000000;
00557   static int maxRun = 0;
00558 
00559   if (strcmp(getenv("PGUSER"), "mippdbwrite") != 0) {
00560     cout << "User " << getenv("PGUSER")
00561      << " is not allowed to write to DB" << endl;
00562     return;
00563   }
00564 
00565   TrkChamGeo& db = TrkChamGeo::Instance();
00566   for (int c = 0; c < kNBC; ++c) db.SetCham(c);
00567   if (minRun > run) minRun = run;
00568   if (maxRun < run) maxRun = run;
00569   db.SetRunRange(minRun, maxRun);
00570   db.WriteToDB(TrkChamGeo::kAlignBC, 7); // Write BC alignment only
00571 
00572 }
00573 
00574 ////////////////////////////////////////////////////////////////////////

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