1 // ---------------------------------------------------------------------------------
3 // ---------------------------------------------------------------------------------
4 // Neural Network-based algorithm for track reconstruction in the ALICE ITS.
5 // The class contains all that is necessary in order to perform the tracking
6 // using the ITS clusters in the V2 format.
7 // The class is organized with some embedded objects which serve for
8 // data management, and all setters and getters for all parameters.
9 // The usage of the class from a tracking macro should be based essentially
10 // in the initialization (constructor) and the call of a method which
11 // performs in the right sequence all the operations.
12 // Temporarily (and maybe definitively) all the intermediate steps are
13 // public functions which could be called independently, but they do not
14 // produce any result if all the preventively required steps have not been
16 // ---------------------------------------------------------------------------------
17 // Author: Alberto Pulvirenti (university of Catania)
18 // Email : alberto.pulvirenti@ct.infn.it
19 // ---------------------------------------------------------------------------------
21 #include <Riostream.h>
24 #include <TObjArray.h>
31 #include "AliITSgeom.h"
32 #include "AliITStrackSA.h"
33 #include "AliITSclusterV2.h"
34 #include "AliITStrackV2.h"
36 #include "AliITStrackerANN.h"
38 const Double_t AliITStrackerANN::fgkPi = 3.141592653; // pi
39 const Double_t AliITStrackerANN::fgkHalfPi = 1.570796327; // pi / 2
40 const Double_t AliITStrackerANN::fgkTwoPi = 6.283185307; // 2 * pi
42 ClassImp(AliITStrackerANN)
44 //__________________________________________________________________________________
45 AliITStrackerANN::AliITStrackerANN(const AliITSgeom *geom, Int_t msglev)
46 : AliITStrackerV2(geom), fMsgLevel(msglev)
48 /**************************************************************************
50 CONSTRUCTOR (standard-to-use version)
53 1) the ITS geometry used in the generated event
54 2) the flag for log-messages writing
56 The AliITSgeometry is used along the class,
57 in order to translate the local AliITSclusterV2 coordinates
58 into the Global reference frame, which is necessary for the
59 Neural Network algorithm to operate.
60 In case of serialized use, the log messages should be excluded,
61 in order to save real execution time.
64 - all pointer data members are initialized
65 (if possible, otherwise are set to NULL)
66 - all numeric data members are initialized to
67 values which allow the Neural Network to operate
68 even if nothing is externally set.
70 NOTE: it is possible that tracking an event
71 with these default values results in a non-sense.
73 **************************************************************************/
78 fGeom = (AliITSgeom*)geom;
80 // Initialize the array of first module indexes per layer
81 fNLayers = geom->GetNlayers();
82 fFirstModInLayer = new Int_t[fNLayers + 1];
83 for (i = 0; i < fNLayers; i++) {
84 fFirstModInLayer[i] = fGeom->GetModuleIndex(i + 1, 1, 1);
86 fFirstModInLayer[fNLayers] = geom->GetIndexMax();
88 // initialization: no curvature cut steps
92 // initialization: 4 sectors (one for each quadrant)
94 fSectorWidth = fgkHalfPi;
96 // initialization: theta offset of 20 degrees
97 fPolarInterval = 20.0;
99 // initialization: array structure not defined
100 fStructureOK = kFALSE;
102 // initialization: vertex in the origin
107 // initialization: uninitialized point array
110 // initialization: very large (unuseful) cut values
112 for (ilayer = 0; ilayer < 6; ilayer++) {
113 fThetaCut2D[ilayer] = TMath::Pi();
114 fThetaCut3D[ilayer] = TMath::Pi();
115 fHelixMatchCut[ilayer] = 1.0;
118 // initialization: inictial activation range between 0.3 and 0.7
122 // initialization: neural network operation & weights
124 fStabThreshold = 0.001;
125 fGain2CostRatio = 1.0;
129 // initialization: uninitialized array of neurons
132 // initialization: uninitialized array of tracks
136 //__________________________________________________________________________________
137 void AliITStrackerANN::SetCuts
138 (Int_t ncurv, Double_t *curv, Double_t *theta2D, Double_t *theta3D, Double_t *helix)
140 /**************************************************************************
144 Allows for the definition of all kind of geometric cuts
145 which have been studied in for the creation of a neuron
146 from a pair of clusters C1 and C2 on consecutive layers.
147 Neuron will be created only if the pair passes ALL of these cuts.
149 At the moment, we define 4 kinds of geometrical cuts:
150 a) cut on the difference of the polar 'theta' angle;
151 b) cut on the angle between origin->C1 and C1->C2 in space;
152 c) cut on the curvature of the circle passing
153 through C1, C2 and the primary vertex;
154 d) cut on heli-matching of the same three points.
157 1) the number of curvature cut steps
158 2) the array of curvature cuts for each step
159 (its dimension is given by the argument 1)
160 3) array of 5 cut values (one for each consecutive lauer pair)
162 4) array of 5 cut values (one for each consecutive lauer pair)
164 5) array of 5 cut values (one for each consecutive lauer pair)
168 - gets the values for each cut and stores them in data members
169 - in the case of curvature cuts, the cut array
170 (whose size is not fixed) is allocated
172 NOTE: in case that the user wants to set onyl ONE of the 4 cuts array,
173 he can simply pass NULL arguments for other cuts, and (eventually)
174 a ZERO as the first argument (if curvature cuts have not to be set).
176 Anyway, all the cuts have to be set at least once.
178 **************************************************************************/
183 /*** Curvature cut setting ***/
185 // first of all, the curvature cuts are sorted in increasing order
186 // (from the smallest to the largest one)
187 Int_t *ind = new Int_t[ncurv];
188 TMath::Sort(ncurv, curv, ind, kFALSE);
189 // then, the curvature cut array is allocated and filled
190 // (a message with the list of defined cuts can be optionally shown)
191 fCurvCut = new Double_t[ncurv];
192 if (fMsgLevel >= 1) cout << "Number of curvature cuts: " << ncurv << endl;
193 for (i = 0; i < ncurv; i++) {
194 fCurvCut[i] = curv[ind[i]];
195 if (fMsgLevel >= 1) cout << " - " << fCurvCut[i] << endl;
199 /*** 'Fixed' cuts setting ***/
201 // checks what cuts have to be set
202 Bool_t doTheta2D = (theta2D != 0);
203 Bool_t doTheta3D = (theta3D != 0);
204 Bool_t doHelix = (helix != 0);
205 // sets the cuts for all layer pairs
206 for (i = 0; i < fNLayers - 1; i++) {
207 if (doTheta2D) fThetaCut2D[i] = theta2D[i];
208 if (doTheta3D) fThetaCut3D[i] = theta3D[i];
209 if (doHelix) fHelixMatchCut[i] = helix[i];
211 // if required, lists the cuts
212 if (!fMsgLevel < 2) return;
213 cout << "Theta 2D cuts: ";
215 cout << "<not set>" << endl;
219 for (i = 0; i < fNLayers - 1; i++) {
220 cout << "For layers " << i << " --> " << i + 1;
221 cout << " cut = " << fThetaCut2D[i] << endl;
224 cout << "---" << endl;
225 cout << "Theta 3D cuts: ";
227 cout << "<not set>" << endl;
231 for (i = 0; i < fNLayers - 1; i++) {
232 cout << "For layers " << i << " --> " << i + 1;
233 cout << " cut = " << fThetaCut3D[i] << endl;
236 cout << "---" << endl;
237 cout << "Helix-match cuts: ";
239 cout << "<not set>" << endl;
243 for (i = 0; i < fNLayers - 1; i++) {
244 cout << "For layers " << i << " --> " << i + 1;
245 cout << " cut = " << fHelixMatchCut[i] << endl;
248 cout << "---" << endl;
251 //__________________________________________________________________________________
252 Bool_t AliITStrackerANN::GetGlobalXYZ
254 Double_t &x, Double_t &y, Double_t &z, Double_t &ex2, Double_t &ey2, Double_t &ez2)
256 /**************************************************************************
258 LOCAL TO GLOBAL TRANSLATOR
260 Taking information from the ITS geometry stored in the class,
261 gets a stored AliITScluster and calculates it coordinates
262 and errors in the global reference frame.
263 These values are stored in the variables,
264 which are passed by reference.
267 1) reference index for the cluster to use
268 2) (by reference) place to store the global X-coord into
269 3) (by reference) place to store the global Y-coord into
270 4) (by reference) place to store the global Z-coord into
271 5) (by reference) place to store the global X-coord error into
272 6) (by reference) place to store the global Y-coord error into
273 7) (by reference) place to store the global Z-coord error into
276 essentially, determines the ITS module index from the
277 detector index of the AliITSclusterV2 object, and extracts
278 the roto-translation from the ITS geometry, to convert
279 the local module coordinates into the global ones.
282 - kFALSE if the given cluster index points to a non-existing
283 cluster, or if the layer number makes no sense (< 0 or > 6).
284 - otherwise, kTRUE (meaning a successful operation).
286 **************************************************************************/
288 // checks if the layer is correct
289 Int_t ilayer = (refIndex & 0xf0000000) >> 28;
290 if (ilayer < 0 || ilayer >= fNLayers) {
291 Error("GetGlobalXYZ", "Wrong layer number: %d [range: %d - %d]", ilayer, 0, fNLayers);
294 // checks if the referenced cluster exists and corresponds to the passed reference
295 AliITSclusterV2 *refCluster = (AliITSclusterV2*) GetCluster(refIndex);
297 Error("GetGlobalXYZ", "Cluster not found for index %d", refIndex);
301 // determine the detector number
302 Int_t detID = refCluster->GetDetectorIndex() + fFirstModInLayer[ilayer];
304 // get rotation matrix
306 fGeom->GetRotMatrix(detID, rot);
308 // get translation vector
310 fGeom->GetTrans(detID, tx, ty, tz);
312 // determine r and phi for the reference conversion
313 Double_t r = -(Double_t)tx * rot[1] + (Double_t)ty * rot[0];
314 if (ilayer == 0) r = -r;
315 Double_t phi = TMath::ATan2(rot[1],rot[0]);
316 if (ilayer == 0) phi -= fgkPi;
318 // sets values for X, Y, Z in global coordinates and their errors
319 Double_t cosPhi = TMath::Cos(phi);
320 Double_t sinPhi = TMath::Sin(phi);
321 x = r*cosPhi + refCluster->GetY()*sinPhi;
322 y = -r*sinPhi + refCluster->GetY()*cosPhi;
323 z = refCluster->GetZ();
324 ex2 = refCluster->GetSigmaY2()*sinPhi*sinPhi;
325 ey2 = refCluster->GetSigmaY2()*cosPhi*cosPhi;
326 ez2 = refCluster->GetSigmaZ2();
331 //__________________________________________________________________________________
332 AliITStrackerANN::AliITSnode* AliITStrackerANN::AddNode(Int_t refIndex)
334 /**************************************************************************
336 GENERATOR OF NEURAL NODES
338 Fills the array of neural 'nodes', which are the ITS clusters
339 translated in the global reference frame.
340 Given that the global coordinates are used many times, they are
341 stored in a well-defined structure, in the form of an embedded class.
342 Moreover, this class allows a faster navigation among points
343 and neurons, by means of some object arrays, storing only the
344 neurons which start from, or end to, the given node.
345 Finally, each node contains all the other nodes which match it
346 with respect to the fixed walues, in order to perform a faster
347 neuron-creation phase.
350 1) reference index of the correlated AliITSclusterV2 object
353 - allocates the new AliITSnode objects
354 - initializes its object arrays
355 - from the global coordinates, calculates the
356 'phi' and 'theta' coordinates, in order to store it
357 into the correct theta-slot and azimutal sector.
360 - the pointer of the creater AliITSnode object
361 - in case of errors, a waring is given and a NULL is returned
363 **************************************************************************/
365 // create object and set the reference
366 AliITSnode *node = new AliITSnode;
368 Warning("AddNode", "Error occurred when allocating AliITSnode");
371 node->ClusterRef() = refIndex;
373 // calls the conversion function, which makes also some checks
374 // (layer number within range, existence of referenced cluster)
377 node->X(), node->Y(), node->Z(),
378 node->ErrX2(), node->ErrY2(), node->ErrZ2()
381 // initializes the object arrays
382 node->Matches() = new TObjArray;
383 node->InnerOf() = new TObjArray;
384 node->OuterOf() = new TObjArray;
386 // finds azimutal and polar sector (in degrees)
387 Double_t phi = node->GetPhi() * 180.0 / fgkPi;
388 Double_t theta = node->GetTheta() * 180.0 / fgkPi;
389 Int_t isector = (Int_t)(phi / fSectorWidth);
390 Int_t itheta = (Int_t)theta;
391 Int_t ilayer = (refIndex & 0xf0000000) >> 28;
393 // selects the right TObjArray to store object into
394 TObjArray *sector = (TObjArray*)fNodes[ilayer][itheta]->At(isector);
395 sector->AddLast(node);
400 //__________________________________________________________________________________
401 void AliITStrackerANN::CreateArrayStructure(Int_t nsectors)
403 /**************************************************************************
405 ARRAY STRUCTURE CREATOR
407 Creates a structure of nested TObjArray's where the AliITSnode's
409 - the first level is made by 6 arrays (one for each layer)
410 - the second level is made by 180 arrays (one for each int part of theta)
411 - the third level is made by a variable number of arrays
412 (one for each azimutal sector)
415 1) the number of azimutal sectors
418 - calculates the width of each sector, from the argument
419 - allocates and initializes all array levels
420 - sets a flag which tells the user if this NECESSARY operation
421 has been performed (it is needed BEFORE performing tracking)
423 **************************************************************************/
425 // Set the number of sectors and their width.
426 fSectorNum = nsectors;
427 fSectorWidth = 360.0 / (Double_t)fSectorNum;
428 if (fMsgLevel >= 2) {
429 cout << fSectorNum << " sectors --> sector width (degrees) = " << fSectorWidth << endl;
432 // Meaningful indexes
433 Int_t ilayer, isector, itheta;
435 // Mark for the created objects
436 TObjArray *sector = 0;
438 // First index: layer
439 fNodes = new TObjArray**[fNLayers];
440 for (ilayer = 0; ilayer < fNLayers; ilayer++) {
441 fNodes[ilayer] = new TObjArray*[180];
442 for (itheta = 0; itheta < 180; itheta++) fNodes[ilayer][itheta] = 0;
443 for (itheta = 0; itheta < 180; itheta++) {
444 fNodes[ilayer][itheta] = new TObjArray(nsectors);
445 for (isector = 0; isector < nsectors; isector++) {
446 sector = new TObjArray;
448 fNodes[ilayer][itheta]->AddAt(sector, isector);
453 // Sets a checking flag to TRUE.
454 // This flag is checked before filling up the arrays with the points.
455 fStructureOK = kTRUE;
458 //__________________________________________________________________________________
459 Int_t AliITStrackerANN::ArrangePoints(char *exportFile)
461 /**************************************************************************
465 This function assembles the operation from the other above methods,
466 and fills the arrays with the clusters already stored in the
467 layers of the tracker.
468 Then, in order to use this method, the user MUSTs call LoadClusters()
472 1) string for a file name where the global ccordinates
473 of all points can be exported (optional).
474 If this file must not be created, simply pass a NULL argument
477 - for each AliITSclusterV2 in each AliITSlayer, a ne AliITSnode
478 is created and stored in the correct location.
481 - the number of stored points
482 - when errors occur, or no points are found, 0 is returned
484 **************************************************************************/
486 // Check if the array structure has been created
488 Error("ArrangePoints", "Structure NOT defined. Call CreateArrayStructure() first");
492 // meaningful indexes
493 Int_t ientry, ilayer, nentries = 0, index;
496 // if the argument is not NULL, a file is opened
497 fstream file(exportFile, ios::out);
498 if (!exportFile || file.fail()) {
503 // scan all layers for node creation
504 for (ilayer = 0; ilayer < fNLayers; ilayer++) {
505 nPtsLayer = GetNumberOfClustersLayer(ilayer);
506 if (fMsgLevel >= 1) {
507 cout << "Layer " << ilayer << " --> " << nPtsLayer << " clusters" << endl;
509 for (ientry = 0; ientry < nPtsLayer; ientry++) {
510 // calculation of cluster index : (Bit mask LLLLIIIIIIIIIIII)
511 // (L = bits used for layer)
512 // (I = bits used for position in layer)
513 index = ilayer << 28;
515 // add new AliITSnode object
516 AliITSnode *n = AddNode(index);
517 if ( (n != NULL) && exportFile ) {
518 file << index << ' ' << n->X() << ' ' << n->Y() << ' ' << n->Z() << endl;
521 nentries += nPtsLayer;
524 // a conventional final message is put at the end of file
526 file << "-1 0.0 0.0 0.0" << endl;
530 // returns the number of points processed
534 //__________________________________________________________________________________
535 void AliITStrackerANN::StoreOverallMatches()
537 /**************************************************************************
541 Once the nodes have been created, a firs analysis is to check
542 what pairs will satisfy at least the 'fixed' cuts (theta, helix-match)
543 and the most permissive (= larger) curvature cut.
544 All these node pairs are suitable for neuron creation.
545 In fact, when performing a Neural Tracking step, the only further check
546 will be a check against the current curvature step, while the other
548 For thi purpose, each AliITSnode has a data member, named 'fMatches'
549 which contains references to all other AliITSnodes in the successive layer
550 that form, with it, a 'good' pair, with respect to the above cited cuts.
551 Then, in each step for neuron creation, the possible neurons starting from
552 each node will be searched ONLY within the nodes referenced in fMatches.
553 This, of course, speeds up a lot the neuron creation procedure, at the
554 cost of some memory occupation, which results not to be critical.
557 - for each AliITSnode, matches are found according to the criteria
558 expressed above, and stored in the node->fMatches array
560 **************************************************************************/
562 // meaningful counters
563 Int_t ilayer, isector, itheta1, itheta2, check;
564 TObjArray *list1 = 0, *list2 = 0;
565 AliITSnode *node1 = 0, *node2 = 0;
566 Double_t thetaMin, thetaMax;
569 // Scan for each sector
570 for (isector = 0; isector < fSectorNum; isector++) {
571 // sector is chosen once for both lists
572 for (ilayer = 0; ilayer < fNLayers - 1; ilayer++) {
573 for (itheta1 = 0; itheta1 < 180; itheta1++) {
574 list1 = (TObjArray*)fNodes[ilayer][itheta1]->At(isector);
575 TObjArrayIter iter1(list1);
576 while ( (node1 = (AliITSnode*)iter1.Next()) ) {
577 if (node1->IsUsed()) continue;
578 // clear an eventually already present array
579 // node1->Matches()->Clear();
580 // get the global coordinates and defines the theta interval from cut
581 thetaMin = (node1->GetTheta() * 180.0 / fgkPi) - fPolarInterval;
582 thetaMax = (node1->GetTheta() * 180.0 / fgkPi) + fPolarInterval;
583 imin = (Int_t)thetaMin;
584 imax = (Int_t)thetaMax;
585 if (imin < 0) imin = 0;
586 if (imax > 179) imax = 179;
587 // loop on the selected theta slots
588 for (itheta2 = imin; itheta2 <= imax; itheta2++) {
589 list2 = (TObjArray*)fNodes[ilayer + 1][itheta2]->At(isector);
590 TObjArrayIter iter2(list2);
591 while ( (node2 = (AliITSnode*)iter2.Next()) ) {
592 check = PassAllCuts(node1, node2, fCurvNum - 1, fVertexX, fVertexY, fVertexZ);
594 node1->Matches()->AddLast(node2);
596 } // while (node2...)
597 } // for (itheta2...)
598 } // while (node1...)
601 } // for (isector...)
604 //__________________________________________________________________________________
605 Int_t AliITStrackerANN::PassAllCuts
606 (AliITSnode *inner, AliITSnode *outer, Int_t curvStep,
607 Double_t vx, Double_t vy, Double_t vz)
609 // ***********************************************************************************
611 // This check is called in the above method for finding the matches of each node
612 // It check the passed point pair against all the fixed cuts and a specified
613 // curvature cut, among all the ones which have been defined.
614 // The cuts need a vertex-constraint, which is not absolute, but it is passed
618 // 1) the point in the inner layer
619 // 2) the point in the outer layer
620 // 3) curvature step for the curvature cut check (preferably the last)
621 // 4) X of the used vertex
622 // 5) Y of the used vertex
623 // 6) Z of the used vertex
626 // - if necessary, swaps the two points
627 // (the first must be in the innermost of the two layers)
628 // - checks for the theta cuts
629 // - calculates the circle passing through the vertex
630 // and the given points and checks for the curvature cut
631 // - using the radius calculated there, checks for the helix-math cut
634 // 0 - All cuts passed
635 // 1 - theta 2D cut not passed
636 // 2 - theta 3D cut not passed
637 // 3 - curvature calculated but cut not passed
638 // 4 - curvature not calculated (division by zero)
639 // 5 - helix cut not passed
640 // 6 - curvature inxed out of range
642 // ***********************************************************************************
644 // Check for curvature index
645 if (curvStep < 0 || curvStep >= fCurvNum) return 6;
647 // Swap points in order that r1 < r2
648 AliITSnode *temp = 0;
649 if (outer->GetLayer() < inner->GetLayer()) {
655 // All cuts are variable according to the layer of the
656 // innermost point (the other point will surely be
657 // in the further one, because we don't check poin pairs
658 // which are not in adjacent layers)
659 // The reference is given by the innermost point.
660 Int_t layRef = inner->GetLayer();
662 // The calculations in the transverse plane are made in
663 // a shifted reference frame, whose origin corresponds to
664 // the reference point passed in the argument.
665 Double_t xIn = inner->X() - vx;
666 Double_t xOut = outer->X() - vx;
667 Double_t yIn = inner->Y() - vy;
668 Double_t yOut = outer->Y() - vy;
669 Double_t zIn = inner->Z() - vz;
670 Double_t zOut = outer->Z() - vz;
671 Double_t rIn = TMath::Sqrt(xIn*xIn + yIn*yIn);
672 Double_t rOut = TMath::Sqrt(xOut*xOut + yOut*yOut);
674 // Check for theta cut.
675 // There are two different angular cuts:
676 // one w.r. to the angle in the 2-dimensional r-z plane...
678 TVector3 origin2innerRZ(zIn, rIn, 0.0);
679 TVector3 inner2outerRZ(zOut - zIn, rOut - rIn, 0.0);
680 dthetaRZ = origin2innerRZ.Angle(inner2outerRZ) * 180.0 / fgkPi;
681 if (dthetaRZ > fThetaCut2D[layRef]) {
683 // r-z theta cut not passed ---> 1
685 // ...and another w.r. to the angle in the 3-dimensional x-y-z space
687 TVector3 origin2innerXYZ(xIn, yIn, zIn);
688 TVector3 inner2outerXYZ(xOut - xIn, yOut - yIn, zOut - zIn);
689 dthetaXYZ = origin2innerXYZ.Angle(inner2outerXYZ) * 180.0 / fgkPi;
690 if (dthetaXYZ > fThetaCut3D[layRef]) {
692 // x-y-z theta cut not passed ---> 2
695 // Calculation & check of curvature
696 Double_t dx = xIn - xOut;
697 Double_t dy = yIn - yOut;
698 Double_t num = 2.0 * (xIn*yOut - xOut*yIn);
699 Double_t den = rIn*rOut*sqrt(dx*dx + dy*dy);
702 curv = TMath::Abs(num / den);
703 if (curv > fCurvCut[curvStep]) {
705 // curvature too large for cut ---> 3
709 Error("PassAllCuts", "Curvature calculations gives zero denominator");
711 // error: denominator = 0 ---> 4
714 // Calculation & check of helix matching
715 Double_t helMatch = 0.0;
716 Double_t arcIn = 2.0 * rIn * curv;
717 Double_t arcOut = 2.0 * rOut * curv;
718 if (arcIn > -1.0 && arcIn < 1.0)
719 arcIn = TMath::ASin(arcIn);
721 arcIn = ((arcIn > 0.0) ? 0.5 : 1.5) * TMath::Pi();
722 if (arcOut > -1.0 && arcOut < 1.0)
723 arcOut = TMath::ASin(arcOut);
725 arcOut = ((arcOut > 0.0) ? 0.5 : 1.5) * TMath::Pi();
727 arcOut /= 2.0 * curv;
728 if (arcIn == 0.0 || arcOut == 0.0) {
729 Error("PassAllCuts", "Calculation returns zero-length arcs: l1=%f, l2=%f", arcIn, arcOut);
731 // error: circumference arcs seem to equal zero ---> 4
733 helMatch = TMath::Abs(zIn / arcIn - zOut / arcOut);
734 if (helMatch > fHelixMatchCut[layRef]) {
736 // helix match cut not passed ---> 5
739 // ALL CUTS PASSED ---> 0
743 //__________________________________________________________________________________
744 Bool_t AliITStrackerANN::PassCurvCut
745 (AliITSnode *inner, AliITSnode *outer,
747 Double_t vx, Double_t vy, Double_t vz)
749 //***********************************************************************************
751 // This method operates essentially like the above one, but it is used
752 // during a single step of Neural Tracking, where the curvature cut
754 // Then, not necessaryly all the nodes stored in the fMatches array
755 // will be suitable for neuron creation in an intermediate step.
757 // It has the same arguments of the PassAllCuts() method, but
758 // the theta cut is not checked.
759 // Moreover, it has a boolean return value.
761 //***********************************************************************************
763 // Check for curvature index
764 if (curvStep < 0 || curvStep >= fCurvNum) return 6;
766 // Find the reference layer
767 Int_t layIn = inner->GetLayer();
768 Int_t layOut = outer->GetLayer();
769 Int_t layRef = (layIn < layOut) ? layIn : layOut;
771 // The calculations in the transverse plane are made in
772 // a shifted reference frame, whose origin corresponds to
773 // the reference point passed in the argument.
774 Double_t xIn = inner->X() - vx;
775 Double_t xOut = outer->X() - vx;
776 Double_t yIn = inner->Y() - vy;
777 Double_t yOut = outer->Y() - vy;
778 Double_t zIn = inner->Z() - vz;
779 Double_t zOut = outer->Z() - vz;
780 Double_t rIn = TMath::Sqrt(xIn*xIn + yIn*yIn);
781 Double_t rOut = TMath::Sqrt(xOut*xOut + yOut*yOut);
783 // Calculation & check of curvature
784 Double_t dx = xIn - xOut;
785 Double_t dy = yIn - yOut;
786 Double_t num = 2.0 * (xIn*yOut - xOut*yIn);
787 Double_t den = rIn*rOut*sqrt(dx*dx + dy*dy);
791 curv = TMath::Abs(num / den);
792 if (curv > fCurvCut[curvStep]) return kFALSE;
800 curv = TMath::Abs(num / den);
801 if (curv > fCurvCut[curvStep]) {
806 Error("PassAllCuts", "Curvature calculations gives zero denominator");
810 // Calculation & check of helix matching
811 Double_t helMatch = 0.0;
812 Double_t arcIn = 2.0 * rIn * curv;
813 Double_t arcOut = 2.0 * rOut * curv;
814 if (arcIn > -1.0 && arcIn < 1.0)
815 arcIn = TMath::ASin(arcIn);
817 arcIn = ((arcIn > 0.0) ? 0.5 : 1.5) * TMath::Pi();
818 if (arcOut > -1.0 && arcOut < 1.0)
819 arcOut = TMath::ASin(arcOut);
821 arcOut = ((arcOut > 0.0) ? 0.5 : 1.5) * TMath::Pi();
823 arcOut /= 2.0 * curv;
824 if (arcIn == 0.0 || arcOut == 0.0) {
825 Error("PassAllCuts", "Calculation returns zero-length arcs: l1=%f, l2=%f", arcIn, arcOut);
827 // error: circumference arcs seem to equal zero ---> 4
829 helMatch = TMath::Abs(zIn / arcIn - zOut / arcOut);
830 return (helMatch <= fHelixMatchCut[layRef]);
833 //__________________________________________________________________________________
834 void AliITStrackerANN::PrintMatches(Bool_t stop)
836 // Prints the list of points which appear to match
837 // each one of them, according to the preliminary
839 // The arguments states if a pause is required after printing
840 // the matches for each one. In this case, a keypress is needed.
842 TObjArray *sector = 0;
843 Int_t ilayer, isector, itheta, nF;
844 AliITSnode *node1 = 0, *node2 = 0;
845 //AliITSclusterV2 *cluster1 = 0, *cluster2 = 0;
847 for (ilayer = 0; ilayer < 6; ilayer++) {
848 for (isector = 0; isector < fSectorNum; isector++) {
849 for (itheta = 0; itheta < 180; itheta++) {
850 sector = (TObjArray*)fNodes[ilayer][itheta]->At(isector);
851 TObjArrayIter points(sector);
852 while ( (node1 = (AliITSnode*)points.Next()) ) {
853 nF = (Int_t)node1->Matches()->GetEntries();
854 cout << "Node layer: " << node1->GetLayer() << " --> ";
856 cout << "NO Matches!!!" << endl;
859 cout << nF << " Matches" << endl;
860 cout << "Reference cluster: " << hex << node1->ClusterRef() << endl;
861 TObjArrayIter matches(node1->Matches());
862 while ( (node2 = (AliITSnode*)matches.Next()) ) {
863 cout << "Match with " << hex << node2->ClusterRef() << endl;
866 cout << "Press a key" << endl;
875 //__________________________________________________________________________________
876 void AliITStrackerANN::ResetNodes(Int_t isector)
878 /***********************************************************************************
880 NODE NEURON ARRAY CLEANER
882 After a neural tracking step, this method
883 clears the arrays 'fInnerOf' and 'fOuterOf' of each AliITSnode
886 - the sector where the operation is being executed
888 ***********************************************************************************/
890 Int_t ilayer, itheta;
891 TObjArray *sector = 0;
892 AliITSnode *node = 0;
893 for (ilayer = 0; ilayer < fNLayers; ilayer++) {
894 for (itheta = 0; itheta < 180; itheta++) {
895 sector = (TObjArray*)fNodes[ilayer][itheta]->At(isector);
896 TObjArrayIter iter(sector);
898 node = (AliITSnode*)iter.Next();
900 node->InnerOf()->Clear();
901 node->OuterOf()->Clear();
903 delete node->InnerOf();
904 delete node->OuterOf();
905 node->InnerOf() = new TObjArray;
906 node->OuterOf() = new TObjArray;
913 //__________________________________________________________________________________
914 Int_t AliITStrackerANN::CreateNeurons
915 (AliITSnode *node, Int_t curvStep, Double_t vx, Double_t vy, Double_t vz)
917 // This method is used to create alle suitable neurons starting from
918 // a single AliITSnode. Each unit is also stored in the fInnerOf array
919 // of the passed node, and in the fOuterOf array of the other neuron edge.
920 // In the new implementation of the intermediate check steps, a further one
921 // is made, which chechs how well a helix is matched by three points
922 // in three consecutive layers.
923 // Then, a vertex-constrained check is made with vertex located
924 // in a layer L, for points in layers L+1 and L+2.
926 // In order to do this, the creator works recursively, in a tree-visit like operation.
927 // The neurons are effectively created only if the node argument passed is in
928 // the 5th layer (they are created between point of 5th and 6th layer).
929 // If the node is in an inner layer, its coordinates are passet as vertex for a nested
930 // call of the same function in the next two layers.
934 // 2) current curvature cut step
935 // 3) X of referenced temporary (not primary) vertex
936 // 4) Y of referenced temporary (not primary) vertex
937 // 5) Z of referenced temporary (not primary) vertex
940 // - if the layer is the 5th, neurons are created with nodes
941 // in the fMatches array of the passed node
942 // - otherwise, the X, Y, Z of the passed node are given as
943 // vertex and the same procedure is recursively called for all
944 // nodes in the fMatches array of the passed one.
947 // - the total number of neurons created from the passed one
948 // summed with all neurons created from all nodes well matched with it
949 // (assumes a meaning only for nodes in the first layer)
952 Int_t made = 0; // counter
953 Bool_t found = 0; // flag
954 AliITSnode *match = 0; // cursor for a AliITSnode array
955 AliITSneuron *unit = 0; // cursor for a AliITSneuron array
957 // --> Case 0: the passed node has already been used
958 // as member of a track found in a previous step.
959 // In this case, of course, the function exits.
960 if (node->IsUsed()) return 0;
962 // --> Case 1: there are NO well-matched points.
963 // This can happen in all ITS layers, but it happens **for sure**
964 // for a node in the 'last' layer.
965 // Even in this case, the function exits.
966 if (node->Matches()->IsEmpty()) return 0;
968 // --> Case 2: there are well-matched points.
969 // In this case, the function creates a neuron for each
970 // well-matched pair (according to the cuts for the current step)
971 // Moreover, before storing the neuron, a check is necessary
972 // to avoid the duplicate creation of the same neuron twice.
973 // (This could happen if the 3 last arguments of the function
974 // are close enough to cause a good match for the current step
975 // between two points, independently of their difference).
976 // Finally, a node is skipped if it has already been used.
977 // For each matched point for which a neuron is created, the procedure is
978 // recursively called.
979 TObjArrayIter matches(node->Matches());
980 while ( (match = (AliITSnode*)matches.Next()) ) {
981 if (match->IsUsed()) continue;
982 if (!PassCurvCut(node, match, curvStep, vx, vy, vz)) continue;
984 if (!node->InnerOf()->IsEmpty()) {
985 TObjArrayIter presentUnits(node->InnerOf());
986 while ( (unit = (AliITSneuron*)presentUnits.Next()) ) {
987 if (unit->Inner() == node && unit->Outer() == match) {
994 AliITSneuron *unit = new AliITSneuron(node, match, fEdge2, fEdge1);
995 fNeurons->AddLast(unit);
996 node->InnerOf()->AddLast(unit);
997 match->OuterOf()->AddLast(unit);
998 made += CreateNeurons(match, curvStep, node->X(), node->Y(), node->Z());
1002 // Of course, the return value contains the number of neurons
1003 // counting in also the oned created in all levels of recursive calls.
1007 //__________________________________________________________________________________
1008 Int_t AliITStrackerANN::CreateNetwork(Int_t sector, Int_t curvStep)
1010 // This function simply recalls the CreateNeurons() method for each node
1011 // in the first layer, for the current sector.
1012 // This generates the whole network, thanks to the recursive calls.
1015 // 1) current sector
1016 // 2) current curvature step
1019 // - scans the nodes array for all theta's in the current sector
1020 // and layer 0, and calls the CreateNeurons() function.
1022 // removes all eventually present neurons
1023 if (fNeurons) delete fNeurons;
1024 fNeurons = new TObjArray;
1025 fNeurons->SetOwner(kTRUE);
1027 // calls the ResetNodes() function to free the AliITSnode arrays
1028 if (fMsgLevel >= 2) {
1029 cout << "Sector " << sector << " PHI = ";
1030 cout << fSectorWidth * (Double_t)sector << " --> ";
1031 cout << fSectorWidth * (Double_t)(sector + 1) << endl;
1032 cout << "Curvature step " << curvStep << " [cut = " << fCurvCut[curvStep] << "]" << endl;
1036 // meaningful counters
1037 Int_t itheta, neurons = 0;
1038 TObjArray *lstSector = 0;
1041 Double_t vx[6], vy[6], vz[6];
1042 AliITSnode *p[6] = {0, 0, 0, 0, 0, 0};
1043 for (itheta = 0; itheta < 180; itheta++) {
1044 lstSector = (TObjArray*)fNodes[0][itheta]->At(sector);
1045 TObjArrayIter lay0(lstSector);
1046 while ( (p[0] = (AliITSnode*)lay0.Next()) ) {
1047 if (p[0]->IsUsed()) continue;
1051 neurons += CreateNeurons(p[0], curvStep, fVertexX, fVertexY, fVertexZ);
1053 TObjArrayIter lay1(p[0]->Matches());
1054 while ( (p[1] = (AliITSnode*)lay1.Next()) ) {
1055 if (p[1]->IsUsed()) continue;
1056 if (!PassCurvCut(p[0], p[1], curvStep, vx[0], vy[0], vz[0])) continue;
1057 unit = new AliITSneuron;
1058 unit->Inner() = p[0];
1059 unit->Outer() = p[1];
1060 unit->Activation() = gRandom->Rndm() * (fEdge1 - fEdge2) + fEdge2;
1061 unit->fGain = new TObjArray;
1062 fNeurons->AddLast(unit);
1063 p[0]->InnerOf()->AddLast(unit);
1064 p[1]->OuterOf()->AddLast(unit);
1069 TObjArrayIter lay2(p[1]->Matches());
1070 while ( (p[2] = (AliITSnode*)lay2.Next()) ) {
1071 if (p[2]->IsUsed()) continue;
1072 if (!PassCurvCut(p[1], p[2], curvStep, vx[1], vy[1], vz[1])) continue;
1073 unit = new AliITSneuron;
1074 unit->Inner() = p[1];
1075 unit->Outer() = p[2];
1076 unit->Activation() = gRandom->Rndm() * (fEdge1 - fEdge2) + fEdge2;
1077 unit->fGain = new TObjArray;
1078 fNeurons->AddLast(unit);
1079 p[1]->InnerOf()->AddLast(unit);
1080 p[2]->OuterOf()->AddLast(unit);
1085 TObjArrayIter lay3(p[2]->Matches());
1086 while ( (p[3] = (AliITSnode*)lay3.Next()) ) {
1087 if (p[3]->IsUsed()) continue;
1088 if (!PassCurvCut(p[2], p[3], curvStep, vx[2], vy[2], vz[2])) continue;
1089 unit = new AliITSneuron;
1090 unit->Inner() = p[2];
1091 unit->Outer() = p[3];
1092 unit->Activation() = gRandom->Rndm() * (fEdge1 - fEdge2) + fEdge2;
1093 unit->fGain = new TObjArray;
1094 fNeurons->AddLast(unit);
1095 p[2]->InnerOf()->AddLast(unit);
1096 p[3]->OuterOf()->AddLast(unit);
1101 TObjArrayIter lay4(p[3]->Matches());
1102 while ( (p[4] = (AliITSnode*)lay4.Next()) ) {
1103 if (p[4]->IsUsed()) continue;
1104 if (!PassCurvCut(p[3], p[4], curvStep, vx[3], vy[3], vz[3])) continue;
1105 unit = new AliITSneuron;
1106 unit->Inner() = p[3];
1107 unit->Outer() = p[4];
1108 unit->Activation() = gRandom->Rndm() * (fEdge1 - fEdge2) + fEdge2;
1109 unit->fGain = new TObjArray;
1110 fNeurons->AddLast(unit);
1111 p[3]->InnerOf()->AddLast(unit);
1112 p[4]->OuterOf()->AddLast(unit);
1117 TObjArrayIter lay5(p[4]->Matches());
1118 while ( (p[5] = (AliITSnode*)lay5.Next()) ) {
1119 if (p[5]->IsUsed()) continue;
1120 if (!PassCurvCut(p[4], p[5], curvStep, vx[4], vy[4], vz[4])) continue;
1121 unit = new AliITSneuron;
1122 unit->Inner() = p[4];
1123 unit->Outer() = p[5];
1124 unit->Activation() = gRandom->Rndm() * (fEdge1 - fEdge2) + fEdge2;
1125 unit->fGain = new TObjArray;
1126 fNeurons->AddLast(unit);
1127 p[4]->InnerOf()->AddLast(unit);
1128 p[5]->OuterOf()->AddLast(unit);
1137 } // for (itheta...)
1138 // END OF NEW VERSION
1141 for (ilayer = 0; ilayer < 6; ilayer++) {
1142 for (itheta = 0; itheta < 180; itheta++) {
1143 lstSector = (TObjArray*)fNodes[ilayer][itheta]->At(sector_idx);
1144 TObjArrayIter inners(lstSector);
1145 while ( (inner = (AliITSnode*)inners.Next()) ) {
1146 if (inner->GetUser() >= 0) continue;
1147 TObjArrayIter outers(inner->Matches());
1148 while ( (outer = (AliITSnode*)outers.Next()) ) {
1149 if (outer->GetUser() >= 0) continue;
1150 if (!PassCurvCut(inner, outer, curvStep, fVX, fVY, fVZ)) continue;
1151 unit = new AliITSneuron;
1152 unit->Inner() = inner;
1153 unit->Outer() = outer;
1154 unit->Activation() = gRandom->Rndm() * (fEdge1 - fEdge2) + fEdge2;
1155 unit->fGain = new TObjArray;
1156 fNeurons->AddLast(unit);
1157 inner->InnerOf()->AddLast(unit);
1158 outer->OuterOf()->AddLast(unit);
1162 } // for (itheta...)
1163 } // for (ilayer...)
1166 fNeurons->SetOwner();
1170 //__________________________________________________________________________________
1171 Int_t AliITStrackerANN::LinkNeurons()
1173 /***********************************************************************************
1177 Scans the whole neuron array, in order to find all neuron pairs
1178 which are connected in sequence and share a positive weight.
1179 For each of them, an AliITSlink is created, which stores
1180 the weight value, and will allow for a faster calculation
1181 of the total neural input for each updating cycle.
1183 Every neuron contains an object array which stores all AliITSlink
1184 objects which point to sequenced units, with the respective weights.
1187 - the number of link created for the neural network.
1188 If they are 0, no updating can be done and the step is skipped.
1190 ***********************************************************************************/
1192 // meaningful indexes
1194 Double_t weight = 0.0;
1195 TObjArrayIter neurons(fNeurons), *iter;
1196 AliITSneuron *neuron = 0, *test = 0;
1198 // scan in the neuron array
1200 neuron = (AliITSneuron*)neurons.Next();
1202 // checks for neurons startin from its head ( -> )
1203 iter = (TObjArrayIter*)neuron->Inner()->OuterOf()->MakeIterator();
1205 test = (AliITSneuron*)iter->Next();
1207 weight = Weight(test, neuron);
1208 if (weight > 0.0) neuron->Gain()->AddLast(new AliITSlink(weight, test));
1212 // checks for neurons ending in its tail ( >- )
1213 iter = (TObjArrayIter*)neuron->Outer()->InnerOf()->MakeIterator();
1215 test = (AliITSneuron*)iter->Next();
1217 weight = Weight(neuron, test);
1218 if (weight > 0.0) neuron->Gain()->AddLast(new AliITSlink(weight, test));
1226 //__________________________________________________________________________________
1227 Bool_t AliITStrackerANN::Update()
1229 /***********************************************************************************
1231 Performs a single updating cycle.
1234 - for each neuron, gets the activation with the neuron Activate() method
1235 - checks if stability has been reached (compare mean activation variation
1236 with the stability threshold data member)
1239 - kTRUE means that the neural network has stabilized
1240 - kFALSE means that another updating cycle is needed
1242 ***********************************************************************************/
1244 Double_t actVar = 0.0, totDiff = 0.0;
1245 TObjArrayIter iter(fNeurons);
1248 unit = (AliITSneuron*)iter.Next();
1250 actVar = unit->Activate(fTemperature);
1251 // calculation the relative activation variation
1254 totDiff /= fNeurons->GetSize();
1255 return (totDiff < fStabThreshold);
1258 //__________________________________________________________________________________
1259 void AliITStrackerANN::FollowChains(Int_t sector)
1261 /***********************************************************************************
1265 After that the neural network has stabilized,
1266 the final step is to create polygonal chains
1267 of clusters, one in each layer, which represent
1268 the tracks recognized by the neural algorithm.
1269 This is made by means of a choice of the best
1270 neuron among the ones starting from each point.
1272 Once that such neuron is selected, its inner point
1273 will set the 'fNext' field to its outer point, and
1274 similarly, its outer point will set the 'fPrev' field
1276 This defines a bi-directional sequence.
1278 In this procedure, it can happen that many neurons
1279 which have the head of the arrow in a given node, will
1280 all select as best following the neuron with the largest
1281 activation starting in that point.
1282 This results in MANY nodes which have the same 'fNext'.
1283 But, this field will be set to NULL for all these points,
1284 but the only one which is pointed by the 'fPrev' field
1285 of this shared node.
1287 ***********************************************************************************/
1289 // meaningful counters
1290 Int_t itheta, ilayer;
1291 TObjArray *lstSector = 0;
1292 Double_t test = fActMinimum;
1294 AliITSneuron *n = 0;
1296 // scan the whole collection of nodes
1297 for (ilayer = 0; ilayer < fNLayers; ilayer++) {
1298 for (itheta = 0; itheta < 180; itheta++) {
1299 // get the array of point in a given layer/theta-slot/sector
1300 lstSector = (TObjArray*)fNodes[ilayer][itheta]->At(sector);
1301 TObjArrayIter nodes(lstSector);
1302 while ( (p = (AliITSnode*)nodes.Next()) ) {
1303 // if the point is used, it is skipped
1304 if (p->IsUsed()) continue;
1305 // initially, fNext points to nothing, and
1306 // the comparison value is set to the minimum activation
1307 // which allows to say that a neuron is turned 'on'
1308 // a node from which only 'off' neurons start is probably
1309 // a noise point, which will be excluded from the reconstruction.
1312 TObjArrayIter innerof(p->InnerOf());
1313 while ( (n = (AliITSneuron*)innerof.Next()) ) {
1314 // if the examined neuron has not the largest activation
1315 // it is skipped and removed from array of all neurons
1316 // and of its outer point (its inner is the cursor p)
1317 if (n->Activation() < test) {
1318 p->InnerOf()->Remove(n);
1319 n->Outer()->OuterOf()->Remove(n);
1320 delete fNeurons->Remove(n);
1323 // otherwise, its activation becomes the maximum reference
1324 p->Next() = n->Outer();
1325 // at the exit of the while(), the fNext will point
1326 // to the outer node of the neuron starting in p, whose
1327 // activation is the largest.
1329 // the same procedure is made now for all neurons
1330 // for which p is the outer point
1333 TObjArrayIter outerof(p->OuterOf());
1334 while ( (n = (AliITSneuron*)outerof.Next()) ) {
1335 // if the examined neuron has not the largest activation
1336 // it is skipped and removed from array of all neurons
1337 // and of its inner point (its outer is the cursor p)
1338 if (n->Activation() < test) {
1339 p->OuterOf()->Remove(n);
1340 n->Inner()->InnerOf()->Remove(n);
1341 delete fNeurons->Remove(n);
1344 // otherwise, its activation becomes the maximum reference
1345 p->Prev() = n->Inner();
1346 // at the exit of the while(), the fPrev will point
1347 // to the inner node of the neuron ending in p, whose
1348 // activation is the largest.
1350 } // end while (p ...)
1351 } // end for (itheta ...)
1352 } // end for (ilayer ...)
1354 // now the mismatches are solved
1355 Bool_t matchPrev, matchNext;
1356 for (ilayer = 0; ilayer < fNLayers; ilayer++) {
1357 for (itheta = 0; itheta < 180; itheta++) {
1358 // get the array of point in a given layer/theta-slot/sector
1359 lstSector = (TObjArray*)fNodes[ilayer][itheta]->At(sector);
1360 TObjArrayIter nodes(lstSector);
1361 while ( (p = (AliITSnode*)nodes.Next()) ) {
1362 // now p will point to a fPrev and a fNext node.
1363 // Ideally they are placed this way: fPrev --> P --> fNext
1364 // A mismatch happens if the point addressed as fPrev does NOT
1365 // point to p as its fNext. And the same for the point addressed
1367 // In this case, the fNext and fPrev pointers are set to NULL
1368 // and p is excluded from the reconstruction
1369 matchPrev = matchNext= kFALSE;
1370 if (ilayer > 0 && p->Prev() != NULL)
1371 if (p->Prev()->Next() == p) matchPrev = kTRUE;
1372 if (ilayer < 5 && p->Next() != NULL)
1373 if (p->Next()->Prev() == p) matchNext = kTRUE;
1376 else if (ilayer == 5)
1378 if (!matchNext || !matchPrev) {
1379 p->Prev() = p->Next() = 0;
1381 } // end while (p ...)
1382 } // end for (itheta ...)
1383 } // end for (ilayer ...)
1386 //__________________________________________________________________________________
1387 Int_t AliITStrackerANN::SaveTracks(Int_t sector)
1389 /********************************************************************************
1393 Using the fNext and fPrev pointers, the chain is followed
1394 and the track is fitted and saved.
1395 Of course, the track is followed as a chain with a point
1396 for each layer, then the track following starts always
1397 from the clusters in layer 0.
1399 ***********************************************************************************/
1401 // if not initialized, the tracks TobjArray is initialized
1402 if (!fFoundTracks) fFoundTracks = new TObjArray;
1404 // meaningful counters
1405 Int_t itheta, ilayer, l;
1406 TObjArray *lstSector = 0;
1407 AliITSnode *p = 0, *q = 0, **node = new AliITSnode*[fNLayers];
1408 for (l = 0; l < fNLayers; l++) node[l] = 0;
1411 array = new AliITSnode*[fNLayers + 1];
1412 for (l = 0; l <= fNLayers; l++) array[l] = 0;
1413 array[0] = new AliITSnode();
1414 array[0]->X() = fVertexX;
1415 array[0]->Y() = fVertexY;
1416 array[0]->Z() = fVertexZ;
1417 array[0]->ErrX2() = fVertexErrorX;
1418 array[0]->ErrY2() = fVertexErrorY;
1419 array[0]->ErrZ2() = fVertexErrorZ;
1421 Double_t *param = new Double_t[8];
1423 // scan the whole collection of nodes
1424 for (ilayer = 0; ilayer < 1; ilayer++) {
1425 for (itheta = 0; itheta < 180; itheta++) {
1426 // get the array of point in a given layer/theta-slot/sector
1427 lstSector = (TObjArray*)fNodes[ilayer][itheta]->At(sector);
1428 TObjArrayIter nodes(lstSector);
1429 while ( (p = (AliITSnode*)nodes.Next()) ) {
1430 for (q = p; q; q = q->Next()) {
1434 //if (!RiemannFit(fNLayers, node, param)) continue;
1435 // initialization of Kalman Filter Tracking
1436 AliITSclusterV2 *cluster = (AliITSclusterV2*)GetCluster(node[0]->ClusterRef());
1437 Int_t mod = cluster->GetDetectorIndex();
1438 Int_t lay, lad, det;
1439 fGeom->GetModuleId(mod, lay, lad, det);
1440 Float_t y0 = cluster->GetY();
1441 Float_t z0 = cluster->GetZ();
1442 AliITStrackSA* trac = new AliITStrackSA(lay, lad, det,
1444 param[4], param[7], param[3], 1);
1445 for (l = 0; l < fNLayers; l++) {
1446 cluster = (AliITSclusterV2*)GetCluster(node[l]->ClusterRef());
1447 if (cluster) trac->AddClusterV2(l, (node[l]->ClusterRef() & 0x0fffffff)>>0);
1449 AliITStrackV2* ot = new AliITStrackV2(*trac);
1450 ot->ResetCovariance();
1451 ot->ResetClusters();
1452 if (RefitAt(49.,ot,trac)) { //fit from layer 1 to layer 6
1453 AliITStrackV2 *otrack2 = new AliITStrackV2(*ot);
1454 otrack2->ResetCovariance();
1455 otrack2->ResetClusters();
1456 //fit from layer 6 to layer 1
1457 if (RefitAt(3.7,otrack2,ot)) fFoundTracks->AddLast(otrack2);
1459 // end of Kalman Filter fit
1467 //__________________________________________________________________________________
1468 void AliITStrackerANN::ExportTracks(const char *filename) const
1470 // Exports found tracks into a TTree of AliITStrackV2 objects
1471 TFile *file = new TFile(filename, "RECREATE");
1472 TTree *tree = new TTree("TreeT-ANN", "Tracks found in ITS stand-alone with Neural Tracking");
1473 AliITStrackV2 *track = 0;
1474 tree->Branch("Tracks", &track, "AliITStrackV2");
1475 TObjArrayIter tracks(fFoundTracks);
1476 while ( (track = (AliITStrackV2*)tracks.Next()) ) {
1485 //__________________________________________________________________________________
1486 void AliITStrackerANN::CleanNetwork()
1488 // Removes deactivated units from the network
1490 AliITSneuron *unit = 0;
1491 TObjArrayIter neurons(fNeurons);
1492 while ( (unit = (AliITSneuron*)neurons.Next()) ) {
1493 if (unit->Activation() < fActMinimum) {
1494 unit->Inner()->InnerOf()->Remove(unit);
1495 unit->Outer()->OuterOf()->Remove(unit);
1496 delete fNeurons->Remove(unit);
1502 AliITSneuron *enemy = 0;
1504 while ( (unit = (AliITSneuron*)neurons.Next()) ) {
1505 nIn = (Int_t)unit->Inner()->InnerOf()->GetSize();
1506 nOut = (Int_t)unit->Outer()->OuterOf()->GetSize();
1507 if (nIn < 2 && nOut < 2) continue;
1510 TObjArrayIter competing(unit->Inner()->InnerOf());
1511 while ( (enemy = (AliITSneuron*)competing.Next()) ) {
1512 if (unit->Activation() > enemy->Activation()) {
1513 enemy->Inner()->InnerOf()->Remove(enemy);
1514 enemy->Outer()->OuterOf()->Remove(enemy);
1515 delete fNeurons->Remove(enemy);
1518 unit->Inner()->InnerOf()->Remove(unit);
1519 unit->Outer()->OuterOf()->Remove(unit);
1520 delete fNeurons->Remove(unit);
1525 if (removed) continue;
1528 TObjArrayIter competing(unit->Outer()->OuterOf());
1529 while ( (enemy = (AliITSneuron*)competing.Next()) ) {
1530 if (unit->Activation() > enemy->Activation()) {
1531 enemy->Inner()->InnerOf()->Remove(enemy);
1532 enemy->Outer()->OuterOf()->Remove(enemy);
1533 delete fNeurons->Remove(enemy);
1536 unit->Inner()->InnerOf()->Remove(unit);
1537 unit->Outer()->OuterOf()->Remove(unit);
1538 delete fNeurons->Remove(unit);
1547 //__________________________________________________________________________________
1548 Int_t AliITStrackerANN::StoreTracks()
1550 // Stores the tracks found in a single neural tracking step.
1551 // In order to do this, it sects each neuron which has a point
1552 // in the first layer.
1555 // if not initialized, the tracks TobjArray is initialized
1556 if (!fFoundTracks) fFoundTracks = new TObjArray;
1558 Int_t i, check, stored = 0;
1559 Double_t testAct = 0;
1560 AliITSneuron *unit = 0, *cursor = 0, *fwd = 0;
1561 AliITSnode *node = 0;
1562 TObjArrayIter iter(fNeurons), *fwdIter;
1563 TObjArray *removedUnits = new TObjArray(0);
1564 removedUnits->SetOwner(kFALSE);
1565 AliITStrackANN annTrack(fNLayers);
1568 unit = (AliITSneuron*)iter.Next();
1570 if (unit->Inner()->GetLayer() > 0) continue;
1571 annTrack.SetNode(unit->Inner()->GetLayer(), unit->Inner());
1572 annTrack.SetNode(unit->Outer()->GetLayer(), unit->Outer());
1573 node = unit->Outer();
1574 removedUnits->AddLast(unit);
1576 testAct = fActMinimum;
1577 fwdIter = (TObjArrayIter*)node->InnerOf()->MakeIterator();
1580 cursor = (AliITSneuron*)fwdIter->Next();
1582 if (cursor->Used()) continue;
1583 if (cursor->Activation() >= testAct) {
1584 testAct = cursor->Activation();
1589 removedUnits->AddLast(fwd);
1590 node = fwd->Outer();
1591 annTrack.SetNode(node->GetLayer(), node);
1593 check = annTrack.CheckOccupation();
1597 //if (!RiemannFit(fNLayers, trackitem, param)) continue;
1598 if (!annTrack.RiemannFit()) continue;
1599 // initialization of Kalman Filter Tracking
1600 AliITSclusterV2 *cluster = (AliITSclusterV2*)GetCluster(annTrack[0]->ClusterRef());
1601 Int_t mod = cluster->GetDetectorIndex();
1602 Int_t lay, lad, det;
1603 fGeom->GetModuleId(mod, lay, lad, det);
1604 Float_t y0 = cluster->GetY();
1605 Float_t z0 = cluster->GetZ();
1606 AliITStrackSA* trac = new AliITStrackSA(lay, lad, det, y0, z0,
1607 annTrack.Phi(), annTrack.TanLambda(),
1608 annTrack.Curv(), 1);
1609 for (Int_t l = 0; l < fNLayers; l++) {
1610 if (!annTrack[l]) continue;
1611 cluster = (AliITSclusterV2*)GetCluster(annTrack[l]->ClusterRef());
1612 if (cluster) trac->AddClusterV2(l, (annTrack[l]->ClusterRef() & 0x0fffffff)>>0);
1614 AliITStrackV2* ot = new AliITStrackV2(*trac);
1615 ot->ResetCovariance();
1616 ot->ResetClusters();
1617 if (RefitAt(49.,ot,trac)) { //fit from layer 1 to layer 6
1618 AliITStrackV2 *otrack2 = new AliITStrackV2(*ot);
1619 otrack2->ResetCovariance();
1620 otrack2->ResetClusters();
1621 //fit from layer 6 to layer 1
1622 if (RefitAt(3.7,otrack2,ot)) fFoundTracks->AddLast(otrack2);
1624 // end of Kalman Filter fit
1626 for (i = 0; i < fNLayers; i++) {
1627 //node = (AliITSnode*)removedPoints->At(i);
1631 fwdIter = (TObjArrayIter*)removedUnits->MakeIterator();
1633 cursor = (AliITSneuron*)fwdIter->Next();
1643 Double_t AliITStrackerANN::Weight(AliITSneuron *nAB, AliITSneuron *nBC)
1645 /***********************************************************************************
1646 * Calculation of neural weight.
1647 * The implementation of positive neural weight is set only in the case
1648 * of connected units (e.g.: A->B with B->C).
1649 * Given that B is the **common** point. care should be taken to pass
1650 * as FIRST argument the neuron going "to" B, and
1651 * as SECOND argument the neuron starting "from" B
1652 * anyway, a check is put in order to return 0.0 when arguments are not well given.
1653 ***********************************************************************************/
1655 if (nAB->Outer() != nBC->Inner()) {
1656 if (nBC->Outer() == nAB->Inner()) {
1657 AliITSneuron *temp = nAB;
1661 if (fMsgLevel >= 3) {
1662 Info("Weight", "Switching wrongly ordered arguments.");
1665 Warning("Weight", "Not connected segments. Returning 0.0");
1669 AliITSnode *pA = nAB->Inner();
1670 AliITSnode *pB = nAB->Outer();
1671 AliITSnode *pC = nBC->Outer();
1673 TVector3 vAB(pB->X() - pA->X(), pB->Y() - pA->Y(), pB->Z() - pA->Z());
1674 TVector3 vBC(pC->X() - pB->X(), pC->Y() - pB->Y(), pC->Z() - pB->Z());
1676 Double_t weight = 1.0 - sin(vAB.Angle(vBC));
1677 return fGain2CostRatio * TMath::Power(weight, fExponent);
1682 /******************************************
1683 ******************************************
1684 *** AliITStrackerANN::AliITSnode class ***
1685 ******************************************
1686 ******************************************/
1688 //__________________________________________________________________________________
1689 AliITStrackerANN::AliITSnode::AliITSnode()
1690 : fUsed(kFALSE), fClusterRef(-1),
1691 fMatches(NULL), fInnerOf(NULL), fOuterOf(NULL),
1692 fNext(NULL), fPrev(NULL)
1694 // Constructor for the embedded 'AliITSnode' class.
1695 // It initializes all pointer-like objects.
1698 fEX2 = fEY2 = fEZ2 = 0.0;
1701 //__________________________________________________________________________________
1702 AliITStrackerANN::AliITSnode::~AliITSnode()
1704 // Destructor for the embedded 'AliITSnode' class.
1705 // It should clear the object arrays, but it is possible
1706 // that some objects still are useful after the point deletion
1707 // then the arrays are cleared but their objects are owed by
1708 // another TCollection object, and not deleted.
1709 // For safety reasons, all the pointers are set to zero.
1711 fInnerOf->SetOwner(kFALSE);
1715 fOuterOf->SetOwner(kFALSE);
1719 fMatches->SetOwner(kFALSE);
1727 //__________________________________________________________________________________
1728 Double_t AliITStrackerANN::AliITSnode::GetPhi() const
1730 // Calculates the 'phi' (azimutal) angle, and returns it
1731 // in the range between 0 and 2Pi radians.
1734 q = TMath::ATan2(fY,fX);
1738 return q + TMath::TwoPi();
1741 //__________________________________________________________________________________
1742 Double_t AliITStrackerANN::AliITSnode::GetError(Option_t *option)
1744 // Returns the error or the square error of
1745 // values related to the coordinates in different systems.
1746 // The option argument specifies the coordinate error desired:
1748 // "R2" --> error in transverse radius
1749 // "R3" --> error in spherical radius
1750 // "PHI" --> error in azimuthal angle
1751 // "THETA" --> error in polar angle
1752 // "SQ" --> get the square of error
1754 // In order to get the error on the cartesian coordinates
1755 // reference to the inline ErrX2(), ErrY2() adn ErrZ2() methods.
1757 TString opt(option);
1758 Double_t errorSq = 0.0;
1761 if (opt.Contains("R2")) {
1762 errorSq = fX*fX*fEX2 + fY*fY*fEY2;
1763 errorSq /= GetR2sq();
1765 else if (opt.Contains("R3")) {
1766 errorSq = fX*fX*fEX2 + fY*fY*fEY2 + fZ*fZ*fEZ2;
1767 errorSq /= GetR3sq();
1769 else if (opt.Contains("PHI")) {
1770 errorSq = fY*fY*fEX2;
1771 errorSq += fX*fX*fEY2;
1772 errorSq /= GetR2sq() * GetR2sq();
1774 else if (opt.Contains("THETA")) {
1775 errorSq = fZ*fZ * (fX*fX*fEX2 + fY*fY*fEY2);
1776 errorSq += GetR2sq() * GetR2sq() * fEZ2;
1777 errorSq /= GetR3sq() * GetR3sq() * GetR2() * GetR2();
1780 if (!opt.Contains("SQ"))
1781 return TMath::Sqrt(errorSq);
1788 /********************************************
1789 ********************************************
1790 *** AliITStrackerANN::AliITSneuron class ***
1791 ********************************************
1792 ********************************************/
1794 //__________________________________________________________________________________
1795 AliITStrackerANN::AliITSneuron::AliITSneuron
1796 (AliITSnode *inner, AliITSnode *outer, Double_t minAct, Double_t maxAct)
1797 : fUsed(0), fInner(inner), fOuter(outer)
1799 // Default neuron constructor
1800 fActivation = gRandom->Rndm() * (maxAct-minAct) + minAct;
1801 fGain = new TObjArray;
1804 //__________________________________________________________________________________
1805 Double_t AliITStrackerANN::AliITSneuron::Activate(Double_t temperature)
1807 // This computes the new activation of a neuron, and returns
1808 // its activation variation as a consequence of the updating.
1811 // - the 'temperature' parameter for the neural activation logistic function
1814 // - collects the total gain, by summing the products
1815 // of the activation of each sequenced unit by the relative weight.
1816 // - collects the total cost, by summing the activations of
1817 // all competing units
1818 // - passes the sum of gain - cost to the activation function and
1819 // calculates the new activation
1822 // - the difference between the old activation and the new one
1826 Double_t sumGain = 0.0; // total contribution from chained neurons
1827 Double_t sumCost = 0.0; // total contribution from crossing neurons
1828 Double_t input; // total input
1829 Double_t actOld, actNew; // old and new values for the activation
1830 AliITSneuron *linked = 0; // cursor for scanning the neuron arrays (for link check)
1831 AliITSlink *link; // cursor for scanning the synapses arrays (for link check)
1832 TObjArrayIter *iterator = 0; // pointer to the iterator along the neuron arrays
1834 // sum contributions from the correlated units
1835 iterator = (TObjArrayIter*)fGain->MakeIterator();
1837 link = (AliITSlink*)iterator->Next();
1839 sumGain += link->Contribution();
1843 // sum contributions from the competing units:
1844 // the ones which have the same starting point...
1845 iterator = (TObjArrayIter*)fInner->InnerOf()->MakeIterator();
1847 linked = (AliITSneuron*)iterator->Next();
1849 if (linked == this) continue;
1850 sumCost += linked->fActivation;
1853 // ...and the ones which have the same ending point
1854 iterator = (TObjArrayIter*)fOuter->OuterOf()->MakeIterator();
1856 linked = (AliITSneuron*)iterator->Next();
1858 if (linked == this) continue;
1859 sumCost += linked->fActivation;
1862 // calculate the total input as the difference between gain and cost
1863 input = (sumGain - sumCost) / temperature;
1864 actOld = fActivation;
1865 // calculate the final output
1866 #ifdef NEURAL_LINEAR
1867 if (input <= -2.0 * temperature)
1869 else if (input >= 2.0 * temperature)
1872 actNew = input / (4.0 * temperature) + 0.5;
1874 actNew = 1.0 / (1.0 + TMath::Exp(-input));
1876 fActivation = actNew;
1878 // return the activation variation
1879 return TMath::Abs(actNew - actOld);
1884 /******************************************
1885 ******************************************
1886 *** AliITStrackerANN::AliITSlink class ***
1887 ******************************************
1888 ******************************************/
1890 // No methods defined non-inline
1894 /**********************************************
1895 **********************************************
1896 *** AliITStrackerANN::AliITStrackANN class ***
1897 **********************************************
1898 **********************************************/
1900 //__________________________________________________________________________________
1901 AliITStrackerANN::AliITStrackANN::AliITStrackANN(Int_t dim) : fNPoints(dim)
1903 // Default constructor for the AliITStrackANN class
1918 fNode = new AliITSnode*[dim];
1919 for (i = 0; i < dim; i++) fNode[i] = 0;
1923 //__________________________________________________________________________________
1924 Int_t AliITStrackerANN::AliITStrackANN::CheckOccupation() const
1926 // Returns the number of pointers fNode which are not NULL
1929 Int_t count = 0; // counter for how many points are stored in the track
1931 for (i = 0; i < fNPoints; i++) {
1932 if (fNode[i] != NULL) count++;
1938 //__________________________________________________________________________________
1939 Bool_t AliITStrackerANN::AliITStrackANN::RiemannFit()
1941 // Performs the Riemann Sphere fit for the given points to a circle
1942 // and then uses the fit parameters to fit a helix in space.
1945 // - kTRUE if all operations have been performed
1946 // - kFALSE if the numbers risk to lead to an arithmetic violation
1948 Int_t i, j, count, dim = fNPoints;
1950 // First check for all points
1951 count = CheckOccupation();
1952 if (count != fNPoints) {
1953 Error ("AliITStrackANN::RiemannFit", "CheckOccupations returns %d, fNPoints = %d ==> MISMATCH", count, fNPoints);
1959 for (i = 0; i < dim; i++) m1(i,0) = 1.0;
1961 // matrix of Rieman projection coordinates
1962 TMatrixD coords(dim,3);
1963 for (i = 0; i < dim; i++) {
1964 coords(i,0) = fNode[i]->X();
1965 coords(i,1) = fNode[i]->Y();
1966 coords(i,2) = fNode[i]->GetR2sq();
1969 // matrix of weights
1970 Double_t xterm, yterm, ex, ey;
1971 TMatrixD weights(dim,dim);
1972 for (i = 0; i < dim; i++) {
1973 xterm = fNode[i]->X() * fNode[i]->GetPhi() - fNode[i]->Y() / fNode[i]->GetR2();
1974 ex = fNode[i]->ErrX2();
1975 yterm = fNode[i]->Y() * fNode[i]->GetPhi() + fNode[i]->X() / fNode[i]->GetR2();
1976 ey = fNode[i]->ErrY2();
1977 weights(i,i) = fNode[i]->GetR2sq() / (xterm * xterm * ex + yterm * yterm * ey );
1980 // weighted sample mean
1981 Double_t meanX = 0.0, meanY = 0.0, meanW = 0.0, sw = 0.0;
1982 for (i = 0; i < dim; i++) {
1983 meanX += weights(i,i) * coords(i,0);
1984 meanY += weights(i,i) * coords(i,1);
1985 meanW += weights(i,i) * coords(i,2);
1992 // sample covariance matrix
1993 for (i = 0; i < dim; i++) {
1994 coords(i,0) -= meanX;
1995 coords(i,1) -= meanY;
1996 coords(i,2) -= meanW;
1998 TMatrixD coordsT(TMatrixD::kTransposed, coords);
1999 TMatrixD weights4coords(weights, TMatrixD::kMult, coords);
2000 TMatrixD sampleCov(coordsT, TMatrixD::kMult, weights4coords);
2001 for (i = 0; i < 3; i++) {
2002 for (j = i + 1; j < 3; j++) {
2003 sampleCov(i,j) = sampleCov(j,i) = (sampleCov(i,j) + sampleCov(j,i)) * 0.5;
2007 // Eigenvalue problem solving for V matrix
2009 TVectorD eval(3), n(3);
2010 TMatrixD evec = sampleCov.EigenVectors(eval);
2011 if (eval(1) < eval(ileast)) ileast = 1;
2012 if (eval(2) < eval(ileast)) ileast = 2;
2013 n(0) = evec(0, ileast);
2014 n(1) = evec(1, ileast);
2015 n(2) = evec(2, ileast);
2017 // c - known term in the plane intersection with Riemann axes
2018 Double_t c = -(meanX * n(0) + meanY * n(1) + meanW * n(2));
2020 // center and radius of fitted circle
2021 Double_t xc, yc, radius, curv;
2022 xc = -n(0) / (2. * n(2));
2023 yc = -n(1) / (2. * n(2));
2024 radius = (1. - n(2)*n(2) - 4.*c*n(2)) / (4. * n(2) * n(2));
2026 if (radius <= 0.E0) {
2027 Error("RiemannFit", "Radius = %f less than zero!!!", radius);
2030 radius = TMath::Sqrt(radius);
2031 curv = 1.0 / radius;
2033 // evaluating signs for curvature and others
2034 Double_t phi1 = 0.0, phi2, temp1, temp2, phi0, sumdphi = 0.0;
2035 AliITSnode *p = fNode[0];
2037 for (i = 1; i < dim; i++) {
2038 p = (AliITSnode*)fNode[i];
2043 if (temp1 > fgkPi && temp2 < fgkPi)
2045 else if (temp1 < fgkPi && temp2 > fgkPi)
2047 sumdphi += temp2 - temp1;
2050 if (sumdphi < 0.E0) curv = -curv;
2051 Double_t diff, angle = TMath::ATan2(yc, xc);
2053 phi0 = angle + 0.5 * TMath::Pi();
2055 phi0 = angle - 0.5 * TMath::Pi();
2056 diff = angle - phi0;
2058 Double_t dt, temp = TMath::Sqrt(xc*xc + yc*yc) - radius;
2063 //cout << "Dt = " << dt << endl;
2065 Double_t halfC = 0.5 * curv, test;
2066 Double_t *s = new Double_t[dim], *zz = new Double_t[dim], *ws = new Double_t[dim];
2067 for (j = 0; j < 6; j++) {
2071 s[j] = (p->GetR2sq() - dt * dt) / (1. + curv * dt);
2073 if (TMath::Abs(s[j]) < 1.E-6) s[j] = 0.;
2075 Error("RiemannFit", "Square root argument error: %17.15g < 0", s[j]);
2079 s[j] = TMath::Sqrt(s[j]);
2080 //cout << "Curv = " << halfC << " --- s[" << j << "] = " << s[j] << endl;
2082 test = TMath::Abs(s[j]);
2085 s[j] = ((s[j] > 0.) ? 0.99999999999 : -0.9999999999);
2087 Error("RiemannFit", "Value too large: %17.15g", s[j]);
2093 s[j] = TMath::ASin(s[j]) / halfC;
2094 ws[j] = 1.0 / (p->ErrZ2());
2097 // second tep final fit
2098 Double_t s2Sum = 0.0, zSum = 0.0, szSum = 0.0, sSum = 0.0, sumw = 0.0;
2099 for (i = 0; i < dim; i++) {
2100 s2Sum += ws[i] * s[i] * s[i];
2101 zSum += ws[i] * zz[i];
2102 sSum += ws[i] * s[i];
2103 szSum += ws[i] * s[i] * zz[i];
2110 temp = s2Sum - sSum*sSum;
2113 dz = (s2Sum*zSum - sSum*szSum) / temp;
2114 tanL = (szSum - sSum*zSum) / temp;