EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicHtcTask.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicHtcTask.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/02/03
3 //
4 // An attempt to port HERMES & OLYMPUS forward tracking KF code to EicRoot;
5 //
6 
7 #include <assert.h>
8 #include <iostream>
9 
10 #include <TGeoManager.h>
11 #include <TGeoVolume.h>
12 #include <TGeoNode.h>
13 #include <TGeoMaterial.h>
14 #include <TGeoNavigator.h>
15 #include <TClonesArray.h>
16 #include <Math/DistFunc.h>
17 
18 #include <FairRunAna.h>
19 #include <FairField.h>
20 
21 #include <PndTrack.h>
22 
23 #include <3d.h>
24 #include <htclib.h>
25 #include <TrKalmanFilter.h>
26 #include <SensitiveVolume.h>
27 #include <MediaBank.h>
28 #include <MediaSliceArray.h>
29 
30 #include <EicHtcTask.h>
31 #include <EicTrackingDigiHit.h>
32 #include <EicGeoParData.h>
33 #include <EicRunAna.h>
34 
35 using namespace std;
36 
37 #define GCBANK_SIZE 30000000
38 
39 typedef struct {
40  int geant[GCBANK_SIZE];
41 } GCBANK_DEF;
42 #define GCBANK COMMON_BLOCK(GCBANK, gcbank)
44 
46 
47 // ---------------------------------------------------------------------------------------
48 
50  FairTask("EIC HTC Task")
51 {
52  ResetVars();
53 
54  mKalmanFilter = new HtcKalmanFilter(mode);
55 
56  mIdealTrCode = ideal;
57 
58  mFitTrackArray = new TClonesArray("PndTrack");
59 } // EicHtcTask::EicHtcTask()
60 
61 // ---------------------------------------------------------------------------------------
62 
63 // --> FIXME!;
64 #define _MG_CELL_SIZE_ ( 2.0)
65 #define _MG_WIDTH_ (80.0)
66 //#define _MG_CELL_SIZE_ ( 2.0)
67 //#define _MG_WIDTH_ (240.0)
68 
70 {
71  MgridSlice **pslice;
72 
73  // Loop through already defined slices;
74  for(pslice=&mMgslices; *pslice; pslice=&(*pslice)->mNext) ;
75 
76  MgridSlice *slice = *pslice = new MgridSlice();
77  slice->mZ0 = z0;
78 
79  // Create empty mgrid; NB: HRC-mimic would be {4, 3, 1} - if full grid!;
80  int dim[3];
81  double min[3], max[3];
82  // Yes, prefer to use a "normal" Z direction (no fake tricks);
83  MgridDirection *fdir[3];
84  CoordSystem *csystem = new CoordSystem(_CARTESIAN_, 3, XYZ);
85  CoordSystem *fsystem = new CoordSystem(_CARTESIAN_, 3, XYZ);
86 
87  assert(csystem && fsystem);
88 
89  for(int xy=_X_; xy<=_Y_; xy++)
90  {
91  min[xy] = -_MG_WIDTH_/2.;
92  max[xy] = _MG_WIDTH_/2.;
93 
94  // Use hardcoded cell size and "window" size; well, two numbers
95  // should divide well; fix later;
96  dim[xy] = (int)rint(_MG_WIDTH_/_MG_CELL_SIZE_);
97  } /*for xy*/
98 
99  // Reset Z direction; Z-thickness does not matter, clear;
100  dim[_Z_] = 1;
101  min[_Z_] = z0 - 1./2.; max[_Z_] = z0 + 1./2.;
102 
103  // Create direction frames; NB: NO fake Z!;
104  for(int ik=0; ik<3; ik++)
105  fdir[ik] = new MgridDirection(dim[ik], min[ik], max[ik]);
106 
107  // Eventually create and initialize mgrid;
108  slice->mGrid = create_single_mgrid_header((char*)"DUMMY", csystem, fsystem,
110  if (!slice->mGrid || slice->mGrid->initializeAsSingleMgrid(0))
111  {
112  printf("\n !!! Most likely you ran out of memory !!!\n\n");
113  fflush(stdout);
114  return NULL;
115  } /*if*/
116 
117  // Set desired interpolation mode;
118  if (slice->mGrid->setHtcInterpolationMode(&RK_htci)) return NULL;
119 
120  // Fill it right here; may take few seconds if step is small;
121  for(unsigned ip=0; ip<slice->mGrid->getCellNum(); ip++)
122  {
123  TVector3 xx;
124  MgridCell *cell = slice->mGrid->linearAddrToCellPtr(ip);
125 
126  assert(cell);
127  assert(!slice->mGrid->linearAddrToCoord(ip, xx));
128 
129  // --> FIXME: use KF-axis-aligned magnetic field routine;
130  {
131  TVector3 bff;
132 
133  if (!KalmanFilterMagneticField(xx, bff)) slice->mGrid->markCellAsSafe(ip);
134 
135  for(unsigned ip=0; ip<3; ip++)
136  cell->B[ip] = bff[ip];
137  }
138  //if (!kalmanFilterMagneticField(xx, cell->B)) slice->mgrid->markCellAsSafe(ip);
139  //printf("@@@ %4d: %f %f %f\n", ip, cell->B[0], cell->B[1], cell->B[2]);
140  } /*for ip*/
141 
142  return slice;
143 } // HtcKalmanFilter::InitializeMgridSlice()
144 
145 // ---------------------------------------------------------------------------------------
146 
148 {
149  double rtheta = theta*TMath::Pi()/180., rphi = phi*TMath::Pi()/180.;
150 
152  TVector3(sin(rtheta)*cos(rphi), sin(rtheta)*sin(rphi), cos(rtheta));
153 } // EicHtcTask::SetMediaScanThetaPhi()
154 
155 // ---------------------------------------------------------------------------------------
156 
158 {
159  // No length limit; KF axis off (0,0,0) along (0,0,1);
160  t_3d_line zaxis(TVector3(0.0, 0.0, 0.0), TVector3(0.0, 0.0, 1.0));
161  MediaBank *mbank = new MediaBank(zaxis, 0.0);
162 
163  // Some configurability in scan axis;
164  t_3d_line saxis(TVector3(0.0, 0.0, 0.0), mMediaScanDirection);
165  mbank->SetScanLine(saxis);
166 
167  return mbank;
168 } // EicHtcTask::ConfigureMediaBank()
169 
170 // ---------------------------------------------------------------------------------------
171 
172 //
173 // FIXME: take axis slope and boundary epsilon into account!;
174 //
175 
177 {
178  printf("Starting media scan ...\n");
179 
180  // Set up KF axis and media scan axis;
182 
183  TGeoNavigator *navi = (TGeoNavigator *)gGeoManager->GetListOfNavigators()->At(0);
184 
185  // Initialize gGeoManager location & direction to perform the scan;
186  {
187  double x0[3], nx0[3];
188 
189  for(unsigned iq=0; iq<3; iq++) {
190  x0 [iq] = mMediaBank->GetScanLine(). x[iq];
191  nx0[iq] = mMediaBank->GetScanLine().nx[iq];
192  } //for iq
193 
194  gGeoManager->SetCurrentPoint ( x0);
195  gGeoManager->SetCurrentDirection(nx0);
196  }
197 
198  for(TGeoNode *node = gGeoManager->GetCurrentNode(); ; ) {
199  mMediaBank->StartNextLayer(node->GetVolume()->GetMaterial(), gGeoManager->GetCurrentPoint());
200 
201  gGeoManager->FindNextBoundary();
202  mMediaBank->SetCurrentLayerThickness(gGeoManager->GetStep());
203 
204  node = gGeoManager->Step();
205  assert(gGeoManager->IsEntering());
206  // Out of volume or out of tracker -> break;
207  if (mMediaBank->IsOutOfRange() || gGeoManager->IsOutside()) break;
208  } //for inf
209 
210  mMediaBank->Print(); //exit(0);
211 
212  return 0;
213 } // EicHtcTask::PerformMediaScan()
214 
215 // ---------------------------------------------------------------------------------------
216 
218 {
219  TIter next( gGeoManager->GetListOfVolumes() );
220  TGeoVolume *volume;
221 
222  while ((volume=(TGeoVolume*)next())) {
223  TObjArray *arr = volume->GetNodes(); if (!arr) continue;
224 
225  for(unsigned iq=0; iq<arr->GetEntriesFast(); iq++) {
226  TGeoNode *node = (TGeoNode*)arr->At(iq);
227 
228  // FIXME: this should be optimized;
229  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
230  EicDetectorGroup *dgroup = &mIdealTrCode->fGroups[gr];
231 
233  if (!lNode) continue;
234 
235  //printf(" %s\n", node->GetName());
236 
237  // Figure out Z-coordinate;
238  double local[3] = {0,0,0};
239  TVector3 global = LocalToMaster(lNode->mGeoMtx, local);
240  // FIXME: this is a hack!;
241  double z0 = global[2];
242 
243  SensitiveVolume *sv = new SensitiveVolume(lNode, node, z0);
244 
245  for(unsigned nd=0; nd<dgroup->mDigi->mKfNodeTemplates.size(); nd++) {
246  EicKfNodeTemplate *kftmpl = dgroup->mDigi->mKfNodeTemplates[nd];
247 
248  {
249  char buffer[128];
250 
251  // FIXME: naming scheme will be screwed up for say phi-segmented disks (?);
252  snprintf(buffer, 128-1, "%s-%02d-%02d", dgroup->dname->Name().Data(),
253  dgroup->svCounter, nd);
254 
255  // FIXME: later may want to take KF template transformation into account and correct
256  // z0 value accordingly (say project something on scan axis direction);
257  KalmanNode *kfnode = mKalmanFilter->AddNodeWrapper(buffer, NULL, z0, kftmpl->GetMdim());
258  // FIXME: should better overload AddNodeWrapper I guess?;
259  dynamic_cast<TrKalmanNode*>(kfnode)->SetSensitiveVolume(sv);
260  assert(kfnode);
261 
262  printf("%s -> %7.2f cm; %p\n", buffer, kfnode->GetZ(), kftmpl);
263  sv->mKfNodeWrappers.push_back(KalmanNodeWrapper(kfnode, kftmpl, sv->mLogicalNode->mGeoMtx));
264  }
265  } //for nd
266 
267  dgroup->mSensitiveVolumes[lNode] = sv;
268 
269  // Increment sensitive volume and KF node counters;
270  dgroup->svCounter++;
271 
272  break;
273  } //for gr
274  } //for iq
275  } //while
276  //exit(0);
277 
278  return 0;
279 } // EicHtcTask::DeclareSensitiveVolumes()
280 
281 // ---------------------------------------------------------------------------------------
282 
283 //
284 // THINK: get rid of this call once debugging is finished?;
285 //
286 
287 int HtcKalmanFilter::KalmanFilterMagneticField(TVector3 &xx, TVector3 &B)
288 {
289  double x[3] = {xx[0], xx[1], xx[2]}, BB[3];
290  FairField *field = FairRunAna::Instance()->GetField();
291 
292  field->GetFieldValue(x, BB);
293 
294  for(unsigned iq=0; iq<3; iq++)
295  B[iq] = BB[iq];
296 
297  return 0;
298 } // HtcKalmanFilter::KalmanFilterMagneticField()
299 
300 // ---------------------------------------------------------------------------------------
301 
303 {
304  unsigned counter = 0;
305 
306  // FIXME: for now assume each location can have at most 1 hit; if ever want to delegate
307  // this call to FwdTrackFinder be aware, that respective gr_counter loop in FwdTrackFinder::Init()
308  // at present occurs *after* EicHtcTask::Init(), so will have to split
309  // EicHtcTask::ConfigureKalmanFilter() or something like that;
310  for(TrKalmanNodeLocation *location=GetKalmanFilter()->GetLocationHead(); location;
311  location=location->GetNext(KalmanFilter::Forward)) {
312 
313  // FIXME: yet may want to delegate this call to TrKalmanNodeLocation class (so that
314  // it is not exclusively based on whether it has sensitive volumes or not);
315  //if (location->HasSensitiveVolumes()) counter++;
316  //printf("%f -> %d\n", location->GetZ(), location->GetSensitiveVolumeNodeWrapperCount());
317  counter += location->GetSensitiveVolumeNodeWrapperCount();//HasSensitiveVolumes()) counter++;
318  } //for location
319 
320  return counter;
321 } // EicHtcTask::GetMaxPossibleHitCount()
322 
323 // ---------------------------------------------------------------------------------------
324 
326 {
327 #if 1
328  //mKalmanFilter->SetNodeGapMax(10.0);
329 #endif
330 
331  // NB: want to use GetMaxPossibleHitCount() below -> this call has to happen first;
333 
334  // As of 2015/11/07 only a single entry left; yet preserve the scheme like it used to be;
335  StringList *str = new StringList();
336  bool equal_flag = true;
337  // --> FIXME: buffer ~overflow; TString?;
338  char buffer[16384] = "fired-node-min";
339  // This _OLD_ stuff may become needed if ever want to place individual
340  // group limits on missing hit count; for now focus on a sum over all groups;
341 #if _OLD_
342  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
343  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
344 
345  if (!group->svCounter) continue;
346 
347  unsigned len = strlen(buffer);
348  snprintf(buffer+len, 16384-len-1, "%c%s:%d",
349  equal_flag ? '=' : ',', group->dname->Name().Data(), group->ndCounter);
350  equal_flag = false;
351  } //for it
352 #else
353  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
354  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
355 
356  if (!group->svCounter) continue;
357 
358  unsigned len = strlen(buffer);
359  snprintf(buffer+len, 16384-len-1, "%c%s",
360  equal_flag ? '=' : '+', group->dname->Name().Data());
361  equal_flag = false;
362  } //for it
363  unsigned len = strlen(buffer);
364  snprintf(buffer+len, 16384-len-1, ":%d", GetMaxPossibleHitCount() - GetMissingHitCounterMax());
365  printf("%s\n", buffer);
366 #endif
367 
368  str->mString = strdup(buffer);
369  if (!str->mString) return -1;
370 
372  //exit(0);
373 
374  // --> FIXME: make configurable;
375  const char *rk_cfg[] = {
376  "mode=hermes",
377  "small-step-limit=1.8cm",
378  "small-step-order=4",
379  "cell-width-max=2.0cm",
380  "interpolation=3x3x1"
381  };
382  int rk_dim = sizeof(rk_cfg) / sizeof(rk_cfg[0]);
383  char **rk_argv = (char **)malloc(rk_dim * sizeof(char*)); assert(rk_argv);
384  for(int ik=0; ik<rk_dim; ik++)
385  rk_argv[ik] = strdup(rk_cfg[ik]);
386  // Configure Runge-Kutta algorithm; again, XML-ize and feed existing function;
387  runge_kutta_fun(rk_dim, rk_argv);
388 
389  return 0;
390 } // EicHtcTask::ConfigureKalmanFilter()
391 
392 // ---------------------------------------------------------------------------------------
393 
395 {
396  // Call original FairTask Init(); it should be *before* the below GEANT3 calls;
397  FairTask::Init();
398 
400 
401  // Want no limit; a million of seconds should be enough :-)
402  //TIMEST(1000000);
403 
404  // Initialize GEANT common blocks;
405  G3INIT();
406 
407  // Initialize GEANT part of ZEBRA storage;
408  G3ZINIT();
409 
410  // Read in CARD file if needed;
411  //if (card_file_name) GFFGO();
412 
413  // Initialize particle info in the GEANT internals;
414  //GPART();
415 
416  // Call user geometry initialization;
417  //if (!geometry || geometry()) _RETURN_(-1, "geometry() failed\n");
418 
419  // GEANT geometry optimisation, etc;
420  //GGCLOS();
421 
422  // Calculate and initialize the GEANT
423  // cross-sections tables, etc;
424  G3PHYSI();
425 
426  // Import mapping tables which determine sensitive volumes; unify with Calo
427  // digitization code later;
428  {
430 
431  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
432  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
433 
434  if (!group->mGptr) {
435  ioman->GetInFile()->GetObject(group->dname->Name() + "GeoParData", group->mGptr);
436 
437  // Well, missing mapping table is a critical failure;
438  if (!group->mGptr) {
439  std::cout << "-E- Eic"<< group->dname->Name() <<" hit producer: no map found!" << std::endl;
440  return kERROR;
441  } //if
442 
443  group->mGptr->InitializeLookupTables();
444  } //if
445 
446  // Loop through all friend classes and try to read in digitizer header;
447  {
448  // NB: if reconstruction.C was started with FairRunAna rather than EicRunReco, no luck
449  // (I mean do not bother to dig digitization.C file name from FairRunAna internals);
450  EicRunAna *fRun = dynamic_cast<EicRunAna *>(EicRunAna::Instance());
451 
452  if (fRun)
453  //for(unsigned fr=0; fr<fRun->mFriendFiles.size(); fr++) {
454  //TFile fin(fRun->mFriendFiles[fr]);
455  for(unsigned fr=0; fr<fRun->GetFriendFiles().size(); fr++) {
456  TFile fin(fRun->GetFriendFiles()[fr]);
457 
458  if (fin.IsOpen()) {
459 
460  fin.GetObject(group->dname->Name() + "TrackingDigiHitProducer", group->mDigi);
461  fin.Close();
462 
463  if (group->mDigi) break;
464  } //if
465  } //if..for fr
466 
467  // Well, missing digitizer info is a critical failure;
468  if (!group->mDigi) {
469  std::cout << "-E- Eic"<< group->dname->Name() <<
470  " hit producer: no digi layout found!" << std::endl;
471  return kERROR;
472  } //if
473  }
474  } //for it
475  }
476 
477  // Initialize detector logical map lookup tables;
478 #if _OFF_
479  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
480  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
481 
482  group->mGptr->InitializeLookupTables();
483  } //for gr
484 #endif
485 
486  // Loop through all gGeoManager nodes and match them against detector
487  // sensitive volumes;
489 
490  // Perform the media scan;
491  PerformMediaScan();
492 
494 
495  // Get ROOT Manager;
496  {
498 
499  if(!ioman) {
500  Error("EicRecoKalmanFit::Init","RootManager not instantiated!");
501  return kERROR;
502  } //if
503 
504  ioman->Register(mTrackOutBranchName, "Gen", mFitTrackArray, /*fPersistence*/kTRUE);
505  }
506 
507  return kSUCCESS;
508 } // EicHtcTask::Init()
509 
510 // ---------------------------------------------------------------------------------------
511 
512 // FIXME: do it better later;
513 #define _DIM_ 4
514 
516 {
517  // FIXME: re-consider this code;
518  //@@@assert(0);
519 
520  static KfMatrix *x0 = new KfVector(_DIM_);
521 
522  TrKalmanNode *tail = static_cast <TrKalmanNode *>(mKalmanFilter->GetTail());
523 
526  else {
527  // FIXME: pull this out either from MCTrack or from IdealGenTrack;
528  assert(0);
529  } //if
530 
531  {
532  // Want to set 5-th (momentum) component to 0.0; really needed?;
533  double S[5] = {0.0, 0.0, 0.0, 0.0, 0.0};
534 
535 #if _TODAY_
536  // Will depend on selected hit combination -> have to repeat every time new;
537  A->invert(_ARBITRARY_);
538  kfm_multiply(x0, A, b);
539 
540  for(int ip=0; ip<4; ip++)
541  S[ip] = x0->KFV(ip);
542 #endif
543 
544  //printf("@@@ORG: L-fit (tail) -> %7.3f, %7.3f, %7.3f, %7.3f\n",
545  // cm2mm(S[0]), cm2mm(S[1]), S[2], S[3]);
546  //tail->ResetNode(S, mKalmanFilter->GetFieldMode(), _USE_00_);
547  mKalmanFilter->ResetNode(tail, S, _USE_00_);
548  }
549 
550  return 0;
551 } // EicHtcTask::ConstructLinearTrackApproximation()
552 
553 // ---------------------------------------------------------------------------------------
554 
556 {
557  TrKalmanNode * trknode = static_cast <TrKalmanNode*> (node);
558 
559  double S[4], momentum = 1./(trknode->GetInversedMomentum() +
560  (mKalmanFilter->GetFieldMode() == NoField ? 0.0 :
561  mKalmanFilter->GetHead()->GetXs(4)));
562  // Assume just +/-1 for now;
563  int charge = momentum > 0.0 ? 1 : -1;
564 
565  for(unsigned iq=0; iq<4; iq++)
566  S[iq] = node->GetX0(iq) + node->GetXs(iq);
567 
568  t_3d_line line /*= parametrize_straight_line*/(S, node->GetZ());
569 
570  TVector3 x(line.x [0], line.x [1], line.x [2]), dummy(0.1, 0.1, 0.1);
571  TVector3 n(line.nx[0], line.nx[1], line.nx[2]);
572 
573  FairTrackParP tpp(x, fabs(momentum) * n, dummy, dummy, charge, dummy, dummy, dummy);
574 
575  return tpp;
576 } // EicHtcTask::GetFairTrackParP()
577 
578 // ---------------------------------------------------------------------------------------
579 
580 void EicHtcTask::Exec(Option_t* opt)
581 {
582  {
583  static unsigned evCounter;
584 
585  evCounter++;
586  if (!(evCounter%10)) printf("-I- EicHtcTask::Exec() -> event %6d\n", evCounter);
587  }
588 
589  // A separate HTC-specific tree; FIXME: move to Init() later;
590  if (!mHtcBranch) {
591  TTree *outputTree = new TTree(_EIC_HTC_TREE_, "A tree of HTC-reconstructed tracks");
592 
593  // The easiest: do not switch pointers all the time; THINK: multi-threading?;
594  mHtcBranch = outputTree->Branch(_EIC_HTC_TRACK_, _EIC_HTC_BRANCH_,
595  &mHtcTrack, 32000, 99);
596 
597  mHtcTrack = new EicHtcTrack();
598  } //if
599 
600  TrKalmanNode *head = static_cast <TrKalmanNode *>(mKalmanFilter->GetHead());
601  TrKalmanNode *tail = static_cast <TrKalmanNode *>(mKalmanFilter->GetTail());
602 
604  fLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Unknown particle hypothesis ('%s')! \033[0m",
605  mParticleHypothesis.Data());
606 
607  static KfMatrix *A = new KfMatrix(_DIM_, _DIM_), *b = new KfVector(_DIM_);
608 
609  A->Reset(); b->Reset();
610 
611  unsigned firedNodeCounter = 0;
613 
614  //printf("EicHtcTask::Exec() ...\n");
615  //
616  // FIXME: re-arrange loop later in such a way the code can work on >1 track;
617  // for ideal case in principle all is needed is to leave only hits
618  // which were produced by this particular track;
619  //
620 
621  // Loop through all the detectors and allocate hits in KF internal structures;
622  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
623  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
624 
625  //printf("%s\n", group->dname->Name().Data()); assert(group->_fHits);
626  if (!group->_fHits) continue;
627 
628  unsigned hnum = group->_fHits->GetEntriesFast();
629 
630  //printf("%s -> %2d\n", group->dname->Name().Data(), hnum); //assert(group->_fHits);
631  for(unsigned ih=0; ih<hnum; ih++)
632  {
634 
635  //
636  // FIXME: in case of >1 track there should be a hit validity
637  // check right here (and continue if hit does not belong to this track);
638  //
639 
640  // Part of the sensitive volumes may be of no interest (scan axis did not
641  // cross them) -> just skip;
642  SensitiveVolume *sv = group->GetSensitiveVolume(hit);
643  if (!sv) continue;
644 
645  TrKalmanNode *trknode =
646  // NB: yes, in this code do not come into complication of having >1 hit per plane;
647  static_cast <TrKalmanNode*> (sv->mKfNodeWrappers[hit->GetKfNodeID()].GetKfNode(0));
648  // FIXME: make it easy for now -> select clean events only;
649  if (trknode->IsFired()) return;
650  trknode->SetHit(hit);
651 
652  EicKfNodeTemplate *kftmpl = group->mDigi->mKfNodeTemplates[hit->GetKfNodeID()];
653  trknode->SetMeasurementNoise(kftmpl->GetMeasurementNoise(hit));
654  // Explicitely allow this crappy replacement on 1D nodes only;
655  if (trknode->GetMdim() == 1)
656  {
657  static KfMatrix V = KfMatrix(1,1);
658 
659  double resolutionByHand = GetResolutionByHand(trknode->GetName());
660 
661  if (resolutionByHand) {
662  V.KFM(0,0) = resolutionByHand * resolutionByHand;
663  trknode->SetMeasurementNoise(&V);
664  } //if
665  } //if
666 
667  kftmpl->IncrementLinearTrackFitMatrices(sv, hit, tail->GetZ(), A, b);
668 
669  //printf("%s -> %7.2f mm\n", trknode->GetName(), 10.*hit->GetCoord(0));
670 
671  firedNodeCounter++;
672  trknode->SetFiredFlag();
673  } //for ih
674  } //for gr
675 
676  //mKalmanFilter->BuildNodeList();
677 
678  //printf("%d\n", firedNodeCounter);
679  // Basically means import hit file had fewer tracks than simulated.C;
680  if (!firedNodeCounter) return;
681 
682  // Think on this, please ...;
684 
686 
688  //printf("@@@: K-fit (tail) -> %7.3f, %7.3f, %7.3f, %7.3f\n",
689  // cm2mm(head->getX0(0)), cm2mm(head->getX0(1)), head->getX0(2), head->getX0(3));
690 
691  // Do iterations by hand; assign head node now;
692  //printf("first fullChain() call ...\n");
693  //head->ResetNode(0, mKalmanFilter->GetFieldMode(), _USE_XF_);
694  mKalmanFilter->ResetNode(head, 0, _USE_XF_);
695  // Well, if _TRUST_SMOOTHER_FCN_ bit is set, KF-chain will keep removing
696  // high-chi^2 nodes beyond reasonable limits; think on this and later
697  // optimize KF.xml options (and perhaps allow to activate this bit as well);
698  mKalmanFilter->FullChain(head, tail, KalmanFilter::Forward, _TRUST_FILTER_FCN_/*|_TRUST_SMOOTHER_FCN_*/);
699  //head->ResetNode(0, mKalmanFilter->GetFieldMode(), _USE_XS_);
700  mKalmanFilter->ResetNode(head, 0, _USE_XS_);
701  mKalmanFilter->FullChain(head, tail, KalmanFilter::Forward, _TRUST_FILTER_FCN_/*|_TRUST_SMOOTHER_FCN_*/);
702  //tail->resetNode(0, _USE_XS_);
703  //printf("@@@FIT: K-fit (tail) -> %7.3f, %7.3f, %7.3f, %7.3f\n",
704  // cm2mm(tail->getX0(0)), cm2mm(tail->getX0(1)), tail->getX0(2), tail->getX0(3));
705 #if 0
706  head->resetNode(0, _USE_XS_);
707  printf("@FIT: K-fit (head) -> %7.3f, %7.3f, %7.3f, %7.3f\n\n",
708  cm2mm(head->GetX0(0)), cm2mm(head->GetX0(1)), head->GetX0(2), head->GetX0(3));
709  printf(" --> %f\n", 1/head->GetX0(4));
710 #endif
711  printf(" --> %f\n", 1./(head->GetInversedMomentum() + head->GetXs(4)));
712 
713  //printf("%f\n", head->GetNext(KalmanFilter::Forward)->GetZ());
714 
715  // Assign internal HTC structure;
716  {
717  mHtcTrack->mMomentum = 1./(head->GetInversedMomentum() + head->GetXs(4));
718 
719  // Assign generic information;
723 
724  // Beam coordinate and slope estimate at the head node;
725  for(unsigned xy=0; xy<2; xy++) {
726  mHtcTrack->mBeamCoordXY[xy] =
727  mCoordinateScaleXY * (head->GetX0(xy) + head->GetXs(xy));
728  mHtcTrack->mBeamCoordSigmaXY[xy] = mResidualScaleXY * sqrt(head->GetCS(xy,xy));
729 
730  mHtcTrack->mBeamSlopeXY[xy] =
731  mSlopeScale * (head->GetX0(2+xy) + head->GetXs(2+xy));
732  mHtcTrack->mBeamSlopeSigmaXY[xy] = mSlopeScale * sqrt(head->GetCS(2+xy,2+xy));
733  } //for xy
734 
735  // Clear hit array;
736  mHtcTrack->mHits->clear();
737 
738  // Assign hits;
739  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
740  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
741 
742  if (!group->_fHits) continue;
743 
744  unsigned hnum = group->_fHits->GetEntriesFast();
745 
746  for(unsigned ih=0; ih<hnum; ih++)
747  {
748  EicTrackingDigiHit *hit = (EicTrackingDigiHit*)group->_fHits->At(ih);
749 
751 
752  SensitiveVolume *sv = group->mSensitiveVolumes[group->mGptr->GetLookupTableNode(iz)];
753  TrKalmanNode *trknode =
754  // Yes, use only 0-th hit slot in this code;
755  static_cast <TrKalmanNode*> (sv->mKfNodeWrappers[hit->GetKfNodeID()].GetKfNode(0));
756 
757  // Get the new hit pointer with a proper component number;
758  EicHtcHit *htchit = new EicHtcHit(trknode->GetMdim());
759 
760  htchit->mSmootherChiSquare = trknode->GetSmootherChiSquare();
761  htchit->mSmootherProbability =
762  ROOT::Math::chisquared_cdf_c(trknode->GetSmootherChiSquare(), trknode->GetMdim());
763 
764  // FIXME: assign later if needed (and perhaps state vector itself)!;
765  //assert(trknode->getCS(iq,iq) >= 0.0);
766  //htchit->mDiagCS [iq] = sqrt(trknode->getCS(iq,iq) >= 0.0 ? trknode->getCS(iq,iq) : 0.0);
767 
768  // Figure out coordinate and residual scale factors;
769  double coordinateScale = mCoordinateScaleXY;
770  double residualScale = mResidualScaleXY;
771  //printf("%f %f %f\n", mResidualScaleXY, residualScale, radius);
772 
773  for(unsigned iq=0; iq<trknode->GetMdim(); iq++) {
774  EicHtcHitComponent *comp = htchit->mComponents + iq;
775 
776  // Local coordinates;
777  comp->mLocalCoord1D = coordinateScale * hit->_GetCoord(iq);
778 
779  comp->mXsResidual = residualScale * trknode->GetRs(iq);
780  comp->mXmResidual = residualScale * trknode->GetRm(iq);
781 
782  comp->mResolution = residualScale * sqrt(trknode->GetV(iq,iq));
783  //printf("%s -> %f\n", trknode->getName(), comp->mResolution);
784 
785  // FIXME: perhaps can do it better?;
786  //assert(trknode->getRS(iq,iq) >= 0.0 && trknode->getRM(iq,iq) >= 0.0);
787  if (trknode->GetRS(iq,iq) < 0.0 || trknode->GetRM(iq,iq) < 0.0) goto _next_hit;
788 
789  comp->mSigmaRS = residualScale * sqrt(trknode->GetRS(iq,iq));
790  //comp->mSigmaRS = mResidualScale * sqrt(trknode->getCS(iq,iq));
791  comp->mSigmaRM = residualScale * sqrt(trknode->GetRM(iq,iq));
792  //printf("%d/%d/%d -> %f\n", iz, hit->GetKfNodeID(), iq, comp->mSigmaRM);
793  } //for iq
794 
795  for(unsigned xy=0; xy<2; xy++)
796  htchit->mGlobalCoordXY[xy] =
797  // Right, mCoordinateScaleXY here for all detector types;
798  mCoordinateScaleXY * (trknode->GetX0(xy) + trknode->GetXs(xy));
799 
800  // Assign map element;
801  {
802  kEntry key = kEntry(group->dname->NAME().Data(),
803  std::pair<unsigned, unsigned>(iz, hit->GetKfNodeID()));
804  (*mHtcTrack->mHits)[key] = htchit;
805  }
806 
807  _next_hit:
808  continue;
809  } //for ih
810  } //for gr
811  }
812 
813  // Recover this stuff later as well, please;
814 #if _LATER_
815  mFitTrackArray->Delete();
816 
817  {
818  PndTrack *fitTrack = new PndTrack();
819 
820  TClonesArray& trkRef = *mFitTrackArray;
821  Int_t size = trkRef.GetEntriesFast();
822 
823  // Construct coordinates at the head node;
824  FairTrackParP first = GetFairTrackParP(head);
825  FairTrackParP last = GetFairTrackParP(tail);
826 
827  double value = mKalmanFilter->GetFilterChiSquareCCDF();//Probability();
828 
829  // FIXME: a test hack for now;
830 #if _OLD_
831  for(unsigned gr=0; gr<mIdealTrCode->fGroups.size(); gr++) {
832  EicDetectorGroup *group = &mIdealTrCode->fGroups[gr];
833 
834  if (!group->_fHits) continue;
835 
836  unsigned hnum = group->_fHits->GetEntriesFast();
837  //printf("%s -> %d hits\n", group->dname->Name().Data(), hnum);
838 
839  for(unsigned ih=0; ih<hnum; ih++)
840  {
841  EicTrackingDigiHit *hit = (EicTrackingDigiHit*)group->_fHits->At(ih);
842 
843  //const EicGeoMap *fmap = group->mGptr->GetMapPtrViaHitMultiIndex(hit->fMultiIndex);
844  //assert(fmap);
845 
846  ULogicalIndex_t iz = group->mGptr->GeantMultiToLogicalIndex(hit->fMultiIndex);
847  printf("%s %d\n", group->dname->Name().Data(), iz);
848 
849  // Yes, now want to select UVA tracker;
850  //if (group->dname->NAME().EqualTo("UVA")) {
851  if (group->dname->NAME().EqualTo("TRK") && iz == 1) {
852  //if (group->dname->NAME().EqualTo("SBS") && iz == 1) {
853 #ifdef _1D_
854  for(unsigned xy=_X_; xy<=_Y_; xy++) {
855  SensitiveVolume *sv = group->mSensitiveVolumes[iz*2+xy];
856 #else
857  SensitiveVolume *sv = group->mSensitiveVolumes[iz];
858 #endif
859 
860  // FIXME: yes, prefer a clean case now; once re-arrange into track loop, fix this;
861  //if (sv->_fHits.size()) return;
862 
863  //sv->_fHits.push_back(hit);
864 
865  TrKalmanNode *trknode = static_cast <TrKalmanNode*> (sv->firstKfNode);
866  // --> FIXME (multiple hits);
867  //trknode->_ht = 0;
868 
869  {
870 #ifdef _1D_
871  //static KfMatrix V = KfMatrix(1,1);
872  //V.KFM(0,0) = hit->fCov[xy ? 3 : 0];
873 #else
874  //printf("%f: %7.5f vs %7.5f + %7.5f\n", trknode->getZ(),
875  // hit->fLocalCoord[0], trknode->getX0(0), trknode->getXs(0));
876  // Test purposes anyway: [cm] -> [um];
877  {
878  double global[3] = {trknode->getX0(0) + trknode->getXs(0),
879  trknode->getX0(1) + trknode->getXs(1),
880  trknode->getZ()}, local[3];
881  //double global[3] = {trknode->getX0(0) + trknode->getXm(0),
882  // trknode->getX0(1) + trknode->getXm(1),
883  // trknode->getZ()}, local[3];
884  const LogicalVolumeLookupTableEntry *node = group->mGptr->GetLookupTableNode(iz);
885 
886  node->mGeoMtx->MasterToLocal(global, local);
887 
888  //value = 1E4*(local[0] - hit->fLocalCoord[0]);
889  value = 1E4*(local[1] - hit->fLocalCoord[1]);
890 
891  //value = 1E4*trknode->getXm(1));
892 
893  //value = 1000.*(trknode->getX0(2) + trknode->getXs(2));
894  //value = 1000.*(trknode->getX0(3) + trknode->getXs(3));
895  }
896  // FLYSUB preliminary: want Y-component in the real data;
897  //value = 1E4*(trknode->getX0(1) + trknode->getXs(1) - hit->fLocalCoord[1]);
898  //value = hit->fLocalCoord[1];
899  //value = 1E4*sqrt(trknode->getCS(0,0));
900 
901  //static KfMatrix V = KfMatrix(2,2);
902  //V.KFM(0,1) = V.KFM(1,0) = hit->mCov[1];
903  //V.KFM(0,0) = hit->mCov[0];
904  //V.KFM(1,1) = hit->mCov[3];
905  //printf("%f %f %f\n", hit->mCov[1], hit->mCov[0], hit->mCov[3]);
906 #endif
907  //trknode->setMeasurementNoise(V);
908 
909  // Increment linear track fit matrices; --> FIXME (not only 0-th hit);
910  //incrementLinearTrackFitMatrices(sv, hit, A, b);
911  }
912 
913  //sv->firstKfNode->setFiredFlag();
914 #ifdef _1D_
915  } //for xy
916 #endif
917  } //if
918  } //for ih
919  } //for gr
920 #endif
921 
922  //if (first.GetQ() == -1) printf("@@CH@@\n");
923  //printf("%f -> %f ... %f\n", mKalmanFilter->getFilterChiSquare(), mKalmanFilter->getFilterProbability(), value);
924  PndTrack* pndTrack = new(trkRef[size]) PndTrack(first, last, fitTrack->GetTrackCand(),
926  }
927 #endif
928 
929  mHtcBranch->GetTree()->Fill();
930 } // EicHtcTask::Exec()
931 
932 // ---------------------------------------------------------------------------------------
933 
935 {
936  if (mPersistency && mHtcBranch) {
937  mHtcBranch->GetTree()->GetCurrentFile()->cd();
938  mHtcBranch->GetTree()->Write();
939  } //if
940 
941  // Save object itself;
942  Write();
943 
945 } // EicHtcTask::FinishTask()
946 
947 // ---------------------------------------------------------------------------------------
948 
949 void EicHtcTask::Print(Option_t* option) const
950 {
951  TTask::Print();
952 
953  printf("Forced particle type: %s; momentum seed: %8.2f [GeV/c]\n",
955 } // EicHtcTask::Print()
956 
957 // ---------------------------------------------------------------------------------------
958 
960 {
961  int ret = strcmp(lh.first, rh.first);
962 
963  // The actual meaning of ">" and "<" is not important; this std::map
964  // arrangement is just to speed up the access;
965  if (ret)
966  return ret < 0;
967  else {
968  std::pair<unsigned, unsigned> &lhh = lh.second, &rhh = rh.second;
969 
970  if (lhh.first == rhh.first)
971  return lhh.second < rhh.second;
972  else
973  return lhh.first < rhh.first;
974  } //if
975 } // HitKeyCompare()
976 
977 // ---------------------------------------------------------------------------------------
978 
979 const EicHtcHit* EicHtcTrack::GetHit(const char *detName, unsigned group, unsigned node) const
980 {
981  kEntry key = kEntry(detName, std::pair<unsigned, unsigned>(group, node));
982 
983  if (mHits->find(key) == mHits->end()) return 0;
984 
985  return (*mHits)[key];
986 } // EicHtcTrack::GetHit()
987 
988 // ---------------------------------------------------------------------------------------
989 
994