00001
00002
00003
00004
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
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
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
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 , int )
00103 {
00104 }
00105
00106
00107
00108 void AlignBC::EndRun(int run, int )
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 )
00217 {
00218 double w[12];
00219 double u[12];
00220 double du[12];
00221 double z[12];
00222 double cosA[12];
00223 double sinA[12];
00224 short plane[12];
00225
00226 ChamDrift& drift = ChamDrift::Instance();
00227
00228
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
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
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
00292
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
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
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);
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
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);
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);
00571
00572 }
00573
00574