00001
00002
00003
00004
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 )
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
00143
00144 fZ0 = GMIPPGeo::Instance(run).Target().CenterPos()[2];
00145 TrkCand::Init(fZ0);
00146
00147 double saveBy = BFMagnet::JGG().ByAtCenter();
00148
00149
00150
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
00160 for (int c = kBC1; c < kNCham; ++c) db.SetCham(c);
00161 db.WriteToDB(TrkChamGeo::kBCFixed, 0770);
00162
00163
00164
00165 if (fNTrackWithBC >= fMinTracksBC) {
00166 if (fAdjustBField && fabs(saveBy) > 0.5) {
00167
00168
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
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 )
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
00264 FitCurvedTrack(nClust, u, w, z, cosA, sinA, fZ0, lambdaX, lambdaY,
00265 par, 0);
00266
00267
00268 double lamX[kNCham][kNPlane], lamY[kNCham][kNPlane];
00269 CalcLambda(fZ0, lamX, lamY, par, chamber[0] / 4, chamber[nClust - 1] / 4);
00270
00271
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
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 )
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
00349 FitCurvedTrack(nt->nclust, u, w, z, cosA, sinA,
00350 fZ0, lambdaX, lambdaY, par, 0);
00351
00352
00353 double lamX[kNCham][kNPlane], lamY[kNCham][kNPlane];
00354 CalcLambda(fZ0, lamX, lamY, par, 0, kPWC6);
00355
00356
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
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
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
00415
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);
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
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
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
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
00491
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
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
00553
00554
00555
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) {
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