1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
17 Revision 1.10 2000/10/03 13:51:57 egangler
18 Removal of useless dependencies via forward declarations
20 Revision 1.9 2000/10/02 16:58:29 egangler
21 Cleaning of the code :
24 -> some useless includes removed or replaced by "class" statement
26 Revision 1.8 2000/07/03 11:54:57 morsch
27 AliMUONSegmentation and AliMUONHitMap have been replaced by AliSegmentation and AliHitMap in STEER
28 The methods GetPadIxy and GetPadXxy of AliMUONSegmentation have changed name to GetPadI and GetPadC.
30 Revision 1.7 2000/06/28 15:16:35 morsch
31 (1) Client code adapted to new method signatures in AliMUONSegmentation (see comments there)
32 to allow development of slat-muon chamber simulation and reconstruction code in the MUON
33 framework. The changes should have no side effects (mostly dummy arguments).
34 (2) Hit disintegration uses 3-dim hit coordinates to allow simulation
35 of chambers with overlapping modules (MakePadHits, Disintegration).
37 Revision 1.6 2000/06/28 12:19:18 morsch
38 More consequent seperation of global input data services (AliMUONClusterInput singleton) and the
39 cluster and hit reconstruction algorithms in AliMUONClusterFinderVS.
40 AliMUONClusterFinderVS becomes the base class for clustering and hit reconstruction.
41 It requires two cathode planes. Small modifications in the code will make it usable for
42 one cathode plane and, hence, more general (for test beam data).
43 AliMUONClusterFinder is now obsolete.
45 Revision 1.5 2000/06/28 08:06:10 morsch
46 Avoid global variables in AliMUONClusterFinderVS by seperating the input data for the fit from the
47 algorithmic part of the class. Input data resides inside the AliMUONClusterInput singleton.
48 It also naturally takes care of the TMinuit instance.
50 Revision 1.4 2000/06/27 16:18:47 gosset
51 Finally correct implementation of xm, ym, ixm, iym sizes
52 when at least three local maxima on cathode 1 or on cathode 2
54 Revision 1.3 2000/06/22 14:02:45 morsch
55 Parameterised size of xm[], ym[], ixm[], iym[] correctly implemented (PH)
56 Some HP scope problems corrected (PH)
58 Revision 1.2 2000/06/15 07:58:48 morsch
59 Code from MUON-dev joined
61 Revision 1.1.2.3 2000/06/09 21:58:33 morsch
62 Most coding rule violations corrected.
64 Revision 1.1.2.2 2000/02/15 08:33:52 morsch
65 Error in calculation of contribution map for double clusters (Split method) corrected (A.M.)
66 Error in determination of track list for double cluster (FillCluster method) corrected (A.M.)
67 Revised and extended SplitByLocalMaxima method (Isabelle Chevrot):
68 - For clusters with more than 2 maxima on one of the cathode planes all valid
69 combinations of maxima on the two cathodes are preserved. The position of the maxima is
70 taken as the hit position.
71 - New FillCluster method with 2 arguments to find tracks associated to the clusters
72 defined above added. (Method destinction by argument list not very elegant in this case,
73 should be revides (A.M.)
74 - Bug in if-statement to handle maximum 1 maximum per plane corrected
75 - Two cluster per cathode but only 1 combination valid is handled.
76 - More rigerous treatment of 1-2 and 2-1 combinations of maxima.
80 #include "AliMUONClusterFinderVS.h"
81 #include "AliMUONDigit.h"
82 #include "AliMUONRawCluster.h"
83 #include "AliSegmentation.h"
84 #include "AliMUONResponse.h"
85 #include "AliMUONClusterInput.h"
86 #include "AliMUONHitMapA1.h"
95 #include <TPostScript.h>
100 #include <iostream.h>
102 //_____________________________________________________________________
103 // This function is minimized in the double-Mathieson fit
104 void fcnS2(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
105 void fcnS1(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
106 void fcnCombiS1(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
107 void fcnCombiS2(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag);
109 ClassImp(AliMUONClusterFinderVS)
111 AliMUONClusterFinderVS::AliMUONClusterFinderVS()
113 // Default constructor
114 fInput=AliMUONClusterInput::Instance();
117 fTrack[0]=fTrack[1]=-1;
120 AliMUONClusterFinderVS::AliMUONClusterFinderVS(
121 const AliMUONClusterFinderVS & clusterFinder)
123 // Dummy copy Constructor
127 void AliMUONClusterFinderVS::Decluster(AliMUONRawCluster *cluster)
129 // Decluster by local maxima
130 SplitByLocalMaxima(cluster);
133 void AliMUONClusterFinderVS::SplitByLocalMaxima(AliMUONRawCluster *c)
135 // Split complex cluster by local maxima
138 fInput->SetCluster(c);
140 fMul[0]=c->fMultiplicity[0];
141 fMul[1]=c->fMultiplicity[1];
144 // dump digit information into arrays
149 for (cath=0; cath<2; cath++) {
151 for (i=0; i<fMul[cath]; i++)
154 fDig[i][cath]=fInput->Digit(cath, c->fIndexMap[i][cath]);
156 fIx[i][cath]= fDig[i][cath]->fPadX;
157 fIy[i][cath]= fDig[i][cath]->fPadY;
159 fQ[i][cath] = fDig[i][cath]->fSignal;
160 // pad centre coordinates
162 GetPadC(fIx[i][cath], fIy[i][cath], fX[i][cath], fY[i][cath], fZ[i][cath]);
163 } // loop over cluster digits
164 } // loop over cathodes
170 // Initialise and perform mathieson fits
171 Float_t chi2, oldchi2;
172 // ++++++++++++++++++*************+++++++++++++++++++++
173 // (1) No more than one local maximum per cathode plane
174 // +++++++++++++++++++++++++++++++*************++++++++
175 if ((fNLocal[0]==1 && (fNLocal[1]==0 || fNLocal[1]==1)) ||
176 (fNLocal[0]==0 && fNLocal[1]==1)) {
178 // Perform combined single Mathieson fit
179 // Initial values for coordinates (x,y)
181 // One local maximum on cathodes 1 and 2 (X->cathode 2, Y->cathode 1)
182 if (fNLocal[0]==1 && fNLocal[1]==1) {
185 // One local maximum on cathode 1 (X,Y->cathode 1)
186 } else if (fNLocal[0]==1) {
189 // One local maximum on cathode 2 (X,Y->cathode 2)
194 fprintf(stderr,"\n cas (1) CombiSingleMathiesonFit(c)\n");
195 chi2=CombiSingleMathiesonFit(c);
196 // Int_t ndf = fgNbins[0]+fgNbins[1]-2;
197 // Float_t prob = TMath::Prob(Double_t(chi2),ndf);
198 // prob1->Fill(prob);
199 // chi2_1->Fill(chi2);
201 fprintf(stderr," chi2 %f ",chi2);
210 c->fX[0]=fSeg[0]->GetAnod(c->fX[0]);
211 c->fX[1]=fSeg[1]->GetAnod(c->fX[1]);
213 // If reasonable chi^2 add result to the list of rawclusters
217 // If not try combined double Mathieson Fit
219 fprintf(stderr," MAUVAIS CHI2 !!!\n");
220 if (fNLocal[0]==1 && fNLocal[1]==1) {
221 fXInit[0]=fX[fIndLocal[0][1]][1];
222 fYInit[0]=fY[fIndLocal[0][0]][0];
223 fXInit[1]=fX[fIndLocal[0][1]][1];
224 fYInit[1]=fY[fIndLocal[0][0]][0];
225 } else if (fNLocal[0]==1) {
226 fXInit[0]=fX[fIndLocal[0][0]][0];
227 fYInit[0]=fY[fIndLocal[0][0]][0];
228 fXInit[1]=fX[fIndLocal[0][0]][0];
229 fYInit[1]=fY[fIndLocal[0][0]][0];
231 fXInit[0]=fX[fIndLocal[0][1]][1];
232 fYInit[0]=fY[fIndLocal[0][1]][1];
233 fXInit[1]=fX[fIndLocal[0][1]][1];
234 fYInit[1]=fY[fIndLocal[0][1]][1];
237 // Initial value for charge ratios
240 fprintf(stderr,"\n cas (1) CombiDoubleMathiesonFit(c)\n");
241 chi2=CombiDoubleMathiesonFit(c);
242 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
243 // Float_t prob = TMath::Prob(chi2,ndf);
244 // prob2->Fill(prob);
245 // chi2_2->Fill(chi2);
247 // Was this any better ??
248 fprintf(stderr," Old and new chi2 %f %f ", oldchi2, chi2);
249 if (fFitStat!=0 && chi2>0 && (2.*chi2 < oldchi2)) {
250 fprintf(stderr," Split\n");
251 // Split cluster into two according to fit result
254 fprintf(stderr," Don't Split\n");
260 // +++++++++++++++++++++++++++++++++++++++
261 // (2) Two local maxima per cathode plane
262 // +++++++++++++++++++++++++++++++++++++++
263 } else if (fNLocal[0]==2 && fNLocal[1]==2) {
265 // Let's look for ghosts first
267 Float_t xm[4][2], ym[4][2];
268 Float_t dpx, dpy, dx, dy;
269 Int_t ixm[4][2], iym[4][2];
270 Int_t isec, im1, im2, ico;
272 // Form the 2x2 combinations
273 // 0-0, 0-1, 1-0, 1-1
275 for (im1=0; im1<2; im1++) {
276 for (im2=0; im2<2; im2++) {
277 xm[ico][0]=fX[fIndLocal[im1][0]][0];
278 ym[ico][0]=fY[fIndLocal[im1][0]][0];
279 xm[ico][1]=fX[fIndLocal[im2][1]][1];
280 ym[ico][1]=fY[fIndLocal[im2][1]][1];
282 ixm[ico][0]=fIx[fIndLocal[im1][0]][0];
283 iym[ico][0]=fIy[fIndLocal[im1][0]][0];
284 ixm[ico][1]=fIx[fIndLocal[im2][1]][1];
285 iym[ico][1]=fIy[fIndLocal[im2][1]][1];
289 // ico = 0 : first local maximum on cathodes 1 and 2
290 // ico = 1 : fisrt local maximum on cathode 1 and second on cathode 2
291 // ico = 2 : second local maximum on cathode 1 and first on cathode 1
292 // ico = 3 : second local maximum on cathodes 1 and 2
294 // Analyse the combinations and keep those that are possible !
295 // For each combination check consistency in x and y
300 for (ico=0; ico<4; ico++) {
301 accepted[ico]=kFALSE;
302 // cathode one: x-coordinate
303 isec=fSeg[0]->Sector(ixm[ico][0], iym[ico][0]);
304 dpx=fSeg[0]->Dpx(isec)/2.;
305 dx=TMath::Abs(xm[ico][0]-xm[ico][1]);
306 // cathode two: y-coordinate
307 isec=fSeg[1]->Sector(ixm[ico][1], iym[ico][1]);
308 dpy=fSeg[1]->Dpy(isec)/2.;
309 dy=TMath::Abs(ym[ico][0]-ym[ico][1]);
310 // printf("\n %i %f %f %f %f \n", ico, ym[ico][0], ym[ico][1], dy, dpy );
311 if ((dx <= dpx) && (dy <= dpy)) {
317 accepted[ico]=kFALSE;
322 fprintf(stderr,"\n iacc=2: No problem ! \n");
323 } else if (iacc==4) {
324 fprintf(stderr,"\n iacc=4: Ok, but ghost problem !!! \n");
325 } else if (iacc==0) {
326 fprintf(stderr,"\n iacc=0: I don't know what to do with this !!!!!!!!! \n");
329 // Initial value for charge ratios
330 fQrInit[0]=Float_t(fQ[fIndLocal[0][0]][0])/
331 Float_t(fQ[fIndLocal[0][0]][0]+fQ[fIndLocal[1][0]][0]);
332 fQrInit[1]=Float_t(fQ[fIndLocal[0][1]][1])/
333 Float_t(fQ[fIndLocal[0][1]][1]+fQ[fIndLocal[1][1]][1]);
335 // ******* iacc = 0 *******
336 // No combinations found between the 2 cathodes
337 // We keep the center of gravity of the cluster
342 // ******* iacc = 1 *******
343 // Only one combination found between the 2 cathodes
346 // Initial values for the 2 maxima (x,y)
348 // 1 maximum is initialised with the maximum of the combination found (X->cathode 2, Y->cathode 1)
349 // 1 maximum is initialised with the other maximum of the first cathode
351 fprintf(stderr,"ico=0\n");
356 } else if (accepted[1]){
357 fprintf(stderr,"ico=1\n");
362 } else if (accepted[2]){
363 fprintf(stderr,"ico=2\n");
368 } else if (accepted[3]){
369 fprintf(stderr,"ico=3\n");
375 fprintf(stderr,"\n cas (2) CombiDoubleMathiesonFit(c)\n");
376 chi2=CombiDoubleMathiesonFit(c);
377 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
378 // Float_t prob = TMath::Prob(chi2,ndf);
379 // prob2->Fill(prob);
380 // chi2_2->Fill(chi2);
381 fprintf(stderr," chi2 %f\n",chi2);
383 // If reasonable chi^2 add result to the list of rawclusters
388 // 1 maximum is initialised with the maximum of the combination found (X->cathode 2, Y->cathode 1)
389 // 1 maximum is initialised with the other maximum of the second cathode
391 fprintf(stderr,"ico=0\n");
396 } else if (accepted[1]){
397 fprintf(stderr,"ico=1\n");
402 } else if (accepted[2]){
403 fprintf(stderr,"ico=2\n");
408 } else if (accepted[3]){
409 fprintf(stderr,"ico=3\n");
415 fprintf(stderr,"\n cas (2) CombiDoubleMathiesonFit(c)\n");
416 chi2=CombiDoubleMathiesonFit(c);
417 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
418 // Float_t prob = TMath::Prob(chi2,ndf);
419 // prob2->Fill(prob);
420 // chi2_2->Fill(chi2);
421 fprintf(stderr," chi2 %f\n",chi2);
423 // If reasonable chi^2 add result to the list of rawclusters
427 //We keep only the combination found (X->cathode 2, Y->cathode 1)
428 for (Int_t ico=0; ico<2; ico++) {
430 AliMUONRawCluster cnew;
432 for (cath=0; cath<2; cath++) {
433 cnew.fX[cath]=Float_t(xm[ico][1]);
434 cnew.fY[cath]=Float_t(ym[ico][0]);
435 cnew.fMultiplicity[cath]=c->fMultiplicity[cath];
436 for (i=0; i<fMul[cath]; i++) {
437 cnew.fIndexMap[i][cath]=c->fIndexMap[i][cath];
438 fSeg[cath]->SetPad(fIx[i][cath], fIy[i][cath]);
440 fprintf(stderr,"\nRawCluster %d cath %d\n",ico,cath);
441 fprintf(stderr,"mult_av %d\n",c->fMultiplicity[cath]);
442 FillCluster(&cnew,cath);
444 cnew.fClusterType=cnew.PhysicsContribution();
453 // ******* iacc = 2 *******
454 // Two combinations found between the 2 cathodes
457 // Was the same maximum taken twice
458 if ((accepted[0]&&accepted[1]) || (accepted[2]&&accepted[3])) {
459 fprintf(stderr,"\n Maximum taken twice !!!\n");
461 // Have a try !! with that
462 if (accepted[0]&&accepted[3]) {
473 fprintf(stderr,"\n cas (2) CombiDoubleMathiesonFit(c)\n");
474 chi2=CombiDoubleMathiesonFit(c);
475 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
476 // Float_t prob = TMath::Prob(chi2,ndf);
477 // prob2->Fill(prob);
478 // chi2_2->Fill(chi2);
482 // No ghosts ! No Problems ! - Perform one fit only !
483 if (accepted[0]&&accepted[3]) {
494 fprintf(stderr,"\n cas (2) CombiDoubleMathiesonFit(c)\n");
495 chi2=CombiDoubleMathiesonFit(c);
496 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
497 // Float_t prob = TMath::Prob(chi2,ndf);
498 // prob2->Fill(prob);
499 // chi2_2->Fill(chi2);
500 fprintf(stderr," chi2 %f\n",chi2);
504 // ******* iacc = 4 *******
505 // Four combinations found between the 2 cathodes
507 } else if (iacc==4) {
508 // Perform fits for the two possibilities !!
513 fprintf(stderr,"\n cas (2) CombiDoubleMathiesonFit(c)\n");
514 chi2=CombiDoubleMathiesonFit(c);
515 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
516 // Float_t prob = TMath::Prob(chi2,ndf);
517 // prob2->Fill(prob);
518 // chi2_2->Fill(chi2);
519 fprintf(stderr," chi2 %f\n",chi2);
525 fprintf(stderr,"\n cas (2) CombiDoubleMathiesonFit(c)\n");
526 chi2=CombiDoubleMathiesonFit(c);
527 // ndf = fgNbins[0]+fgNbins[1]-6;
528 // prob = TMath::Prob(chi2,ndf);
529 // prob2->Fill(prob);
530 // chi2_2->Fill(chi2);
531 fprintf(stderr," chi2 %f\n",chi2);
535 } else if (fNLocal[0]==2 && fNLocal[1]==1) {
536 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
537 // (3) Two local maxima on cathode 1 and one maximum on cathode 2
538 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
540 Float_t xm[4][2], ym[4][2];
541 Float_t dpx, dpy, dx, dy;
542 Int_t ixm[4][2], iym[4][2];
543 Int_t isec, im1, ico;
545 // Form the 2x2 combinations
546 // 0-0, 0-1, 1-0, 1-1
548 for (im1=0; im1<2; im1++) {
549 xm[ico][0]=fX[fIndLocal[im1][0]][0];
550 ym[ico][0]=fY[fIndLocal[im1][0]][0];
551 xm[ico][1]=fX[fIndLocal[0][1]][1];
552 ym[ico][1]=fY[fIndLocal[0][1]][1];
554 ixm[ico][0]=fIx[fIndLocal[im1][0]][0];
555 iym[ico][0]=fIy[fIndLocal[im1][0]][0];
556 ixm[ico][1]=fIx[fIndLocal[0][1]][1];
557 iym[ico][1]=fIy[fIndLocal[0][1]][1];
560 // ico = 0 : first local maximum on cathodes 1 and 2
561 // ico = 1 : second local maximum on cathode 1 and first on cathode 2
563 // Analyse the combinations and keep those that are possible !
564 // For each combination check consistency in x and y
569 for (ico=0; ico<2; ico++) {
570 accepted[ico]=kFALSE;
571 isec=fSeg[0]->Sector(ixm[ico][0], iym[ico][0]);
572 dpx=fSeg[0]->Dpx(isec)/2.;
573 dx=TMath::Abs(xm[ico][0]-xm[ico][1]);
574 isec=fSeg[1]->Sector(ixm[ico][1], iym[ico][1]);
575 dpy=fSeg[1]->Dpy(isec)/2.;
576 dy=TMath::Abs(ym[ico][0]-ym[ico][1]);
577 // printf("\n %i %f %f %f %f \n", ico, ym[ico][0], ym[ico][1], dy, dpy );
578 if ((dx <= dpx) && (dy <= dpy)) {
584 accepted[ico]=kFALSE;
596 chi21=CombiDoubleMathiesonFit(c);
597 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
598 // Float_t prob = TMath::Prob(chi2,ndf);
599 // prob2->Fill(prob);
600 // chi2_2->Fill(chi21);
601 fprintf(stderr," chi2 %f\n",chi21);
602 if (chi21<10) Split(c);
603 } else if (accepted[1]) {
608 chi22=CombiDoubleMathiesonFit(c);
609 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
610 // Float_t prob = TMath::Prob(chi2,ndf);
611 // prob2->Fill(prob);
612 // chi2_2->Fill(chi22);
613 fprintf(stderr," chi2 %f\n",chi22);
614 if (chi22<10) Split(c);
617 if (chi21 > 10 && chi22 > 10) {
618 // We keep only the combination found (X->cathode 2, Y->cathode 1)
619 for (Int_t ico=0; ico<2; ico++) {
621 AliMUONRawCluster cnew;
623 for (cath=0; cath<2; cath++) {
624 cnew.fX[cath]=Float_t(xm[ico][1]);
625 cnew.fY[cath]=Float_t(ym[ico][0]);
626 cnew.fMultiplicity[cath]=c->fMultiplicity[cath];
627 for (i=0; i<fMul[cath]; i++) {
628 cnew.fIndexMap[i][cath]=c->fIndexMap[i][cath];
629 fSeg[cath]->SetPad(fIx[i][cath], fIy[i][cath]);
631 fprintf(stderr,"\nRawCluster %d cath %d\n",ico,cath);
632 fprintf(stderr,"mult_av %d\n",c->fMultiplicity[cath]);
633 FillCluster(&cnew,cath);
635 cnew.fClusterType=cnew.PhysicsContribution();
642 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
643 // (3') One local maximum on cathode 1 and two maxima on cathode 2
644 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
645 } else if (fNLocal[0]==1 && fNLocal[1]==2) {
647 Float_t xm[4][2], ym[4][2];
648 Float_t dpx, dpy, dx, dy;
649 Int_t ixm[4][2], iym[4][2];
650 Int_t isec, im1, ico;
652 // Form the 2x2 combinations
653 // 0-0, 0-1, 1-0, 1-1
655 for (im1=0; im1<2; im1++) {
656 xm[ico][0]=fX[fIndLocal[0][0]][0];
657 ym[ico][0]=fY[fIndLocal[0][0]][0];
658 xm[ico][1]=fX[fIndLocal[im1][1]][1];
659 ym[ico][1]=fY[fIndLocal[im1][1]][1];
661 ixm[ico][0]=fIx[fIndLocal[0][0]][0];
662 iym[ico][0]=fIy[fIndLocal[0][0]][0];
663 ixm[ico][1]=fIx[fIndLocal[im1][1]][1];
664 iym[ico][1]=fIy[fIndLocal[im1][1]][1];
667 // ico = 0 : first local maximum on cathodes 1 and 2
668 // ico = 1 : first local maximum on cathode 1 and second on cathode 2
670 // Analyse the combinations and keep those that are possible !
671 // For each combination check consistency in x and y
676 for (ico=0; ico<2; ico++) {
677 accepted[ico]=kFALSE;
678 isec=fSeg[0]->Sector(ixm[ico][0], iym[ico][0]);
679 dpx=fSeg[0]->Dpx(isec)/2.;
680 dx=TMath::Abs(xm[ico][0]-xm[ico][1]);
681 isec=fSeg[1]->Sector(ixm[ico][1], iym[ico][1]);
682 dpy=fSeg[1]->Dpy(isec)/2.;
683 dy=TMath::Abs(ym[ico][0]-ym[ico][1]);
684 // printf("\n %i %f %f %f %f \n", ico, ym[ico][0], ym[ico][1], dy, dpy );
685 if ((dx <= dpx) && (dy <= dpy)) {
688 fprintf(stderr,"ico %d\n",ico);
692 accepted[ico]=kFALSE;
704 chi21=CombiDoubleMathiesonFit(c);
705 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
706 // Float_t prob = TMath::Prob(chi2,ndf);
707 // prob2->Fill(prob);
708 // chi2_2->Fill(chi21);
709 fprintf(stderr," chi2 %f\n",chi21);
710 if (chi21<10) Split(c);
711 } else if (accepted[1]) {
716 chi22=CombiDoubleMathiesonFit(c);
717 // Int_t ndf = fgNbins[0]+fgNbins[1]-6;
718 // Float_t prob = TMath::Prob(chi2,ndf);
719 // prob2->Fill(prob);
720 // chi2_2->Fill(chi22);
721 fprintf(stderr," chi2 %f\n",chi22);
722 if (chi22<10) Split(c);
725 if (chi21 > 10 && chi22 > 10) {
726 //We keep only the combination found (X->cathode 2, Y->cathode 1)
727 for (Int_t ico=0; ico<2; ico++) {
729 AliMUONRawCluster cnew;
731 for (cath=0; cath<2; cath++) {
732 cnew.fX[cath]=Float_t(xm[ico][1]);
733 cnew.fY[cath]=Float_t(ym[ico][0]);
734 cnew.fMultiplicity[cath]=c->fMultiplicity[cath];
735 for (i=0; i<fMul[cath]; i++) {
736 cnew.fIndexMap[i][cath]=c->fIndexMap[i][cath];
737 fSeg[cath]->SetPad(fIx[i][cath], fIy[i][cath]);
739 fprintf(stderr,"\nRawCluster %d cath %d\n",ico,cath);
740 fprintf(stderr,"mult_av %d\n",c->fMultiplicity[cath]);
741 FillCluster(&cnew,cath);
743 cnew.fClusterType=cnew.PhysicsContribution();
750 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
751 // (4) At least three local maxima on cathode 1 or on cathode 2
752 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
753 } else if (fNLocal[0]>2 || fNLocal[1]>2) {
755 Int_t param = fNLocal[0]*fNLocal[1];
758 Float_t ** xm = new Float_t * [param];
759 for (ii=0; ii<param; ii++) xm[ii]=new Float_t [2];
760 Float_t ** ym = new Float_t * [param];
761 for (ii=0; ii<param; ii++) ym[ii]=new Float_t [2];
762 Int_t ** ixm = new Int_t * [param];
763 for (ii=0; ii<param; ii++) ixm[ii]=new Int_t [2];
764 Int_t ** iym = new Int_t * [param];
765 for (ii=0; ii<param; ii++) iym[ii]=new Int_t [2];
768 Float_t dpx, dpy, dx, dy;
771 for (Int_t im1=0; im1<fNLocal[0]; im1++) {
772 for (Int_t im2=0; im2<fNLocal[1]; im2++) {
773 xm[ico][0]=fX[fIndLocal[im1][0]][0];
774 ym[ico][0]=fY[fIndLocal[im1][0]][0];
775 xm[ico][1]=fX[fIndLocal[im2][1]][1];
776 ym[ico][1]=fY[fIndLocal[im2][1]][1];
778 ixm[ico][0]=fIx[fIndLocal[im1][0]][0];
779 iym[ico][0]=fIy[fIndLocal[im1][0]][0];
780 ixm[ico][1]=fIx[fIndLocal[im2][1]][1];
781 iym[ico][1]=fIy[fIndLocal[im2][1]][1];
788 fprintf(stderr,"nIco %d\n",nIco);
789 for (ico=0; ico<nIco; ico++) {
790 fprintf(stderr,"ico = %d\n",ico);
791 isec=fSeg[0]->Sector(ixm[ico][0], iym[ico][0]);
792 dpx=fSeg[0]->Dpx(isec)/2.;
793 dx=TMath::Abs(xm[ico][0]-xm[ico][1]);
794 isec=fSeg[1]->Sector(ixm[ico][1], iym[ico][1]);
795 dpy=fSeg[1]->Dpy(isec)/2.;
796 dy=TMath::Abs(ym[ico][0]-ym[ico][1]);
798 fprintf(stderr,"dx %f dpx %f dy %f dpy %f\n",dx,dpx,dy,dpy);
799 fprintf(stderr," X %f Y %f\n",xm[ico][1],ym[ico][0]);
800 if ((dx <= dpx) && (dy <= dpy)) {
801 fprintf(stderr,"ok\n");
803 AliMUONRawCluster cnew;
804 for (cath=0; cath<2; cath++) {
805 cnew.fX[cath]=Float_t(xm[ico][1]);
806 cnew.fY[cath]=Float_t(ym[ico][0]);
807 cnew.fMultiplicity[cath]=c->fMultiplicity[cath];
808 for (i=0; i<fMul[cath]; i++) {
809 cnew.fIndexMap[i][cath]=c->fIndexMap[i][cath];
810 fSeg[cath]->SetPad(fIx[i][cath], fIy[i][cath]);
812 FillCluster(&cnew,cath);
814 cnew.fClusterType=cnew.PhysicsContribution();
826 void AliMUONClusterFinderVS::FindLocalMaxima(AliMUONRawCluster* c)
828 // Find all local maxima of a cluster
829 printf("\n Find Local maxima !");
833 Int_t cath, cath1; // loops over cathodes
834 Int_t i; // loops over digits
835 Int_t j; // loops over cathodes
839 // counters for number of local maxima
840 fNLocal[0]=fNLocal[1]=0;
841 // flags digits as local maximum
842 Bool_t isLocal[100][2];
843 for (i=0; i<100;i++) {
844 isLocal[i][0]=isLocal[i][1]=kFALSE;
846 // number of next neighbours and arrays to store them
849 // loop over cathodes
850 for (cath=0; cath<2; cath++) {
851 // loop over cluster digits
852 for (i=0; i<fMul[cath]; i++) {
853 // get neighbours for that digit and assume that it is local maximum
854 fSeg[cath]->Neighbours(fIx[i][cath], fIy[i][cath], &nn, x, y);
855 isLocal[i][cath]=kTRUE;
856 Int_t isec= fSeg[cath]->Sector(fIx[i][cath], fIy[i][cath]);
857 Float_t a0 = fSeg[cath]->Dpx(isec)*fSeg[cath]->Dpy(isec);
858 // loop over next neighbours, if at least one neighbour has higher charger assumption
859 // digit is not local maximum
860 for (j=0; j<nn; j++) {
861 if (fHitMap[cath]->TestHit(x[j], y[j])==kEmpty) continue;
862 digt=(AliMUONDigit*) fHitMap[cath]->GetHit(x[j], y[j]);
863 isec=fSeg[cath]->Sector(x[j], y[j]);
864 Float_t a1 = fSeg[cath]->Dpx(isec)*fSeg[cath]->Dpy(isec);
865 if (digt->fSignal/a1 > fQ[i][cath]/a0) {
866 isLocal[i][cath]=kFALSE;
869 // handle special case of neighbouring pads with equal signal
870 } else if (digt->fSignal == fQ[i][cath]) {
871 if (fNLocal[cath]>0) {
872 for (Int_t k=0; k<fNLocal[cath]; k++) {
873 if (x[j]==fIx[fIndLocal[k][cath]][cath]
874 && y[j]==fIy[fIndLocal[k][cath]][cath])
876 isLocal[i][cath]=kFALSE;
878 } // loop over local maxima
879 } // are there already local maxima
881 } // loop over next neighbours
882 if (isLocal[i][cath]) {
883 fIndLocal[fNLocal[cath]][cath]=i;
886 } // loop over all digits
887 } // loop over cathodes
889 printf("\n Found %d %d %d %d local Maxima\n",
890 fNLocal[0], fNLocal[1], fMul[0], fMul[1]);
891 fprintf(stderr,"\n Cathode 1 local Maxima %d Multiplicite %d\n",fNLocal[0], fMul[0]);
892 fprintf(stderr," Cathode 2 local Maxima %d Multiplicite %d\n",fNLocal[1], fMul[1]);
897 if (fNLocal[1]==2 && (fNLocal[0]==1 || fNLocal[0]==0)) {
898 Int_t iback=fNLocal[0];
900 // Two local maxima on cathode 2 and one maximum on cathode 1
901 // Look for local maxima considering up and down neighbours on the 1st cathode only
903 // Loop over cluster digits
907 for (i=0; i<fMul[cath]; i++) {
908 isec=fSeg[cath]->Sector(fIx[i][cath],fIy[i][cath]);
909 dpy=fSeg[cath]->Dpy(isec);
910 dpx=fSeg[cath]->Dpx(isec);
911 if (isLocal[i][cath]) continue;
912 // Pad position should be consistent with position of local maxima on the opposite cathode
913 if ((TMath::Abs(fX[i][cath]-fX[fIndLocal[0][cath1]][cath1]) > dpx/2.) &&
914 (TMath::Abs(fX[i][cath]-fX[fIndLocal[1][cath1]][cath1]) > dpx/2.))
917 // get neighbours for that digit and assume that it is local maximum
918 isLocal[i][cath]=kTRUE;
919 // compare signal to that on the two neighbours on the left and on the right
920 // iNN counts the number of neighbours with signal, it should be 1 or 2
924 ->FirstPad(fX[i][cath], fY[i][cath], fZPlane, 0., dpy);
930 ix = fSeg[cath]->Ix();
931 iy = fSeg[cath]->Iy();
932 // skip the current pad
933 if (iy == fIy[i][cath]) continue;
935 if (fHitMap[cath]->TestHit(ix, iy)!=kEmpty) {
937 digt=(AliMUONDigit*) fHitMap[cath]->GetHit(ix,iy);
938 if (digt->fSignal > fQ[i][cath]) isLocal[i][cath]=kFALSE;
940 } // Loop over pad neighbours in y
941 if (isLocal[i][cath] && iNN>0) {
942 fIndLocal[fNLocal[cath]][cath]=i;
945 } // loop over all digits
946 // if one additional maximum has been found we are happy
947 // if more maxima have been found restore the previous situation
949 "\n New search gives %d local maxima for cathode 1 \n",
952 " %d local maxima for cathode 2 \n",
954 if (fNLocal[cath]>2) {
958 } // 1,2 local maxima
960 if (fNLocal[0]==2 && (fNLocal[1]==1 || fNLocal[1]==0)) {
961 Int_t iback=fNLocal[1];
963 // Two local maxima on cathode 1 and one maximum on cathode 2
964 // Look for local maxima considering left and right neighbours on the 2nd cathode only
968 // Loop over cluster digits
969 for (i=0; i<fMul[cath]; i++) {
970 isec=fSeg[cath]->Sector(fIx[i][cath],fIy[i][cath]);
971 dpx=fSeg[cath]->Dpx(isec);
972 dpy=fSeg[cath]->Dpy(isec);
973 if (isLocal[i][cath]) continue;
974 // Pad position should be consistent with position of local maxima on the opposite cathode
975 if ((TMath::Abs(fY[i][cath]-fY[fIndLocal[0][cath1]][cath1]) > dpy/2.) &&
976 (TMath::Abs(fY[i][cath]-fY[fIndLocal[1][cath1]][cath1]) > dpy/2.))
979 // get neighbours for that digit and assume that it is local maximum
980 isLocal[i][cath]=kTRUE;
981 // compare signal to that on the two neighbours on the left and on the right
983 // iNN counts the number of neighbours with signal, it should be 1 or 2
986 ->FirstPad(fX[i][cath], fY[i][cath], fZPlane, 0., dpx);
992 ix = fSeg[cath]->Ix();
993 iy = fSeg[cath]->Iy();
995 // skip the current pad
996 if (ix == fIx[i][cath]) continue;
998 if (fHitMap[cath]->TestHit(ix, iy)!=kEmpty) {
1000 digt=(AliMUONDigit*) fHitMap[cath]->GetHit(ix,iy);
1001 if (digt->fSignal > fQ[i][cath]) isLocal[i][cath]=kFALSE;
1003 } // Loop over pad neighbours in x
1004 if (isLocal[i][cath] && iNN>0) {
1005 fIndLocal[fNLocal[cath]][cath]=i;
1008 } // loop over all digits
1009 // if one additional maximum has been found we are happy
1010 // if more maxima have been found restore the previous situation
1011 fprintf(stderr,"\n New search gives %d local maxima for cathode 1 \n",fNLocal[0]);
1012 fprintf(stderr,"\n %d local maxima for cathode 2 \n",fNLocal[1]);
1013 // printf("\n New search gives %d %d \n",fNLocal[0],fNLocal[1]);
1014 if (fNLocal[cath]>2) {
1015 fNLocal[cath]=iback;
1017 } // 2,1 local maxima
1021 void AliMUONClusterFinderVS::FillCluster(AliMUONRawCluster* c, Int_t flag, Int_t cath)
1024 // Completes cluster information starting from list of digits
1031 c->fPeakSignal[cath]=c->fPeakSignal[0];
1033 c->fPeakSignal[cath]=0;
1043 // fprintf(stderr,"\n fPeakSignal %d\n",c->fPeakSignal[cath]);
1044 for (Int_t i=0; i<c->fMultiplicity[cath]; i++)
1046 dig= fInput->Digit(cath,c->fIndexMap[i][cath]);
1047 ix=dig->fPadX+c->fOffsetMap[i][cath];
1049 Int_t q=dig->fSignal;
1050 if (!flag) q=Int_t(q*c->fContMap[i][cath]);
1051 // fprintf(stderr,"q %d c->fPeakSignal[ %d ] %d\n",q,cath,c->fPeakSignal[cath]);
1052 if (dig->fPhysics >= dig->fSignal) {
1053 c->fPhysicsMap[i]=2;
1054 } else if (dig->fPhysics == 0) {
1055 c->fPhysicsMap[i]=0;
1056 } else c->fPhysicsMap[i]=1;
1059 // fprintf(stderr,"q %d c->fPeakSignal[cath] %d\n",q,c->fPeakSignal[cath]);
1060 // peak signal and track list
1061 if (q>c->fPeakSignal[cath]) {
1062 c->fPeakSignal[cath]=q;
1063 c->fTracks[0]=dig->fHit;
1064 c->fTracks[1]=dig->fTracks[0];
1065 c->fTracks[2]=dig->fTracks[1];
1066 // fprintf(stderr," c->fTracks[0] %d c->fTracks[1] %d\n",dig->fHit,dig->fTracks[0]);
1070 fSeg[cath]->GetPadC(ix, iy, x, y, z);
1075 } // loop over digits
1076 // fprintf(stderr," fin du cluster c\n");
1080 c->fX[cath]/=c->fQ[cath];
1081 c->fX[cath]=fSeg[cath]->GetAnod(c->fX[cath]);
1082 c->fY[cath]/=c->fQ[cath];
1084 // apply correction to the coordinate along the anode wire
1088 fSeg[cath]->GetPadI(x, y, fZPlane, ix, iy);
1089 fSeg[cath]->GetPadC(ix, iy, x, y, z);
1090 Int_t isec=fSeg[cath]->Sector(ix,iy);
1091 TF1* cogCorr = fSeg[cath]->CorrFunc(isec-1);
1094 Float_t yOnPad=(c->fY[cath]-y)/fSeg[cath]->Dpy(isec);
1095 c->fY[cath]=c->fY[cath]-cogCorr->Eval(yOnPad, 0, 0);
1100 void AliMUONClusterFinderVS::FillCluster(AliMUONRawCluster* c, Int_t cath)
1103 // Completes cluster information starting from list of digits
1113 Float_t xpad, ypad, zpad;
1116 for (Int_t i=0; i<c->fMultiplicity[cath]; i++)
1118 dig = fInput->Digit(cath,c->fIndexMap[i][cath]);
1120 GetPadC(dig->fPadX,dig->fPadY,xpad,ypad, zpad);
1121 fprintf(stderr,"x %f y %f cx %f cy %f\n",xpad,ypad,c->fX[0],c->fY[0]);
1122 dx = xpad - c->fX[0];
1123 dy = ypad - c->fY[0];
1124 dr = TMath::Sqrt(dx*dx+dy*dy);
1128 fprintf(stderr," dr %f\n",dr);
1129 Int_t q=dig->fSignal;
1130 if (dig->fPhysics >= dig->fSignal) {
1131 c->fPhysicsMap[i]=2;
1132 } else if (dig->fPhysics == 0) {
1133 c->fPhysicsMap[i]=0;
1134 } else c->fPhysicsMap[i]=1;
1135 c->fPeakSignal[cath]=q;
1136 c->fTracks[0]=dig->fHit;
1137 c->fTracks[1]=dig->fTracks[0];
1138 c->fTracks[2]=dig->fTracks[1];
1139 fprintf(stderr," c->fTracks[0] %d c->fTracks[1] %d\n",dig->fHit,dig->fTracks[0]);
1142 } // loop over digits
1144 // apply correction to the coordinate along the anode wire
1145 c->fX[cath]=fSeg[cath]->GetAnod(c->fX[cath]);
1148 void AliMUONClusterFinderVS::FindCluster(Int_t i, Int_t j, Int_t cath, AliMUONRawCluster &c){
1152 // Find a super cluster on both cathodes
1155 // Add i,j as element of the cluster
1158 Int_t idx = fHitMap[cath]->GetHitIndex(i,j);
1159 AliMUONDigit* dig = (AliMUONDigit*) fHitMap[cath]->GetHit(i,j);
1160 Int_t q=dig->fSignal;
1161 Int_t theX=dig->fPadX;
1162 Int_t theY=dig->fPadY;
1164 if (q > TMath::Abs(c.fPeakSignal[0]) && q > TMath::Abs(c.fPeakSignal[1])) {
1165 c.fPeakSignal[cath]=q;
1166 c.fTracks[0]=dig->fHit;
1167 c.fTracks[1]=dig->fTracks[0];
1168 c.fTracks[2]=dig->fTracks[1];
1172 // Make sure that list of digits is ordered
1174 Int_t mu=c.fMultiplicity[cath];
1175 c.fIndexMap[mu][cath]=idx;
1177 if (dig->fPhysics >= dig->fSignal) {
1178 c.fPhysicsMap[mu]=2;
1179 } else if (dig->fPhysics == 0) {
1180 c.fPhysicsMap[mu]=0;
1181 } else c.fPhysicsMap[mu]=1;
1185 for (Int_t ind = mu-1; ind >= 0; ind--) {
1186 Int_t ist=(c.fIndexMap)[ind][cath];
1187 Int_t ql=fInput->Digit(cath, ist)->fSignal;
1188 Int_t ix=fInput->Digit(cath, ist)->fPadX;
1189 Int_t iy=fInput->Digit(cath, ist)->fPadY;
1191 if (q>ql || (q==ql && theX > ix && theY < iy)) {
1192 c.fIndexMap[ind][cath]=idx;
1193 c.fIndexMap[ind+1][cath]=ist;
1201 c.fMultiplicity[cath]++;
1202 if (c.fMultiplicity[cath] >= 50 ) {
1203 printf("FindCluster - multiplicity >50 %d \n",c.fMultiplicity[0]);
1204 c.fMultiplicity[cath]=49;
1207 // Prepare center of gravity calculation
1209 fSeg[cath]->GetPadC(i, j, x, y, z);
1215 // Flag hit as "taken"
1216 fHitMap[cath]->FlagHit(i,j);
1218 // Now look recursively for all neighbours and pad hit on opposite cathode
1220 // Loop over neighbours
1224 Int_t xList[10], yList[10];
1225 fSeg[cath]->Neighbours(i,j,&nn,xList,yList);
1226 for (Int_t in=0; in<nn; in++) {
1230 if (fHitMap[cath]->TestHit(ix,iy)==kUnused) {
1231 // printf("\n Neighbours %d %d %d", cath, ix, iy);
1232 FindCluster(ix, iy, cath, c);
1237 Int_t iXopp[50], iYopp[50];
1239 // Neighbours on opposite cathode
1240 // Take into account that several pads can overlap with the present pad
1241 Int_t isec=fSeg[cath]->Sector(i,j);
1247 dx = (fSeg[cath]->Dpx(isec))/2.;
1252 dy = (fSeg[cath]->Dpy(isec))/2;
1254 // loop over pad neighbours on opposite cathode
1255 for (fSeg[iop]->FirstPad(x, y, fZPlane, dx, dy);
1256 fSeg[iop]->MorePads();
1257 fSeg[iop]->NextPad())
1260 ix = fSeg[iop]->Ix(); iy = fSeg[iop]->Iy();
1261 // printf("\n ix, iy: %f %f %f %d %d %d", x,y,z,ix, iy, fSector);
1262 if (fHitMap[iop]->TestHit(ix,iy)==kUnused){
1265 // printf("\n Opposite %d %d %d", iop, ix, iy);
1268 } // Loop over pad neighbours
1269 // This had to go outside the loop since recursive calls inside the iterator are not possible
1272 for (jopp=0; jopp<nOpp; jopp++) {
1273 if (fHitMap[iop]->TestHit(iXopp[jopp],iYopp[jopp]) == kUnused)
1274 FindCluster(iXopp[jopp], iYopp[jopp], iop, c);
1278 //_____________________________________________________________________________
1280 void AliMUONClusterFinderVS::FindRawClusters()
1283 // MUON cluster finder from digits -- finds neighbours on both cathodes and
1284 // fills the tree with raw clusters
1287 // Return if no input datad available
1288 if (!fInput->NDigits(0) && !fInput->NDigits(1)) return;
1290 fSeg[0] = fInput->Segmentation(0);
1291 fSeg[1] = fInput->Segmentation(1);
1293 fHitMap[0] = new AliMUONHitMapA1(fSeg[0], fInput->Digits(0));
1294 fHitMap[1] = new AliMUONHitMapA1(fSeg[1], fInput->Digits(1));
1302 fHitMap[0]->FillHits();
1303 fHitMap[1]->FillHits();
1305 // Outer Loop over Cathodes
1306 for (cath=0; cath<2; cath++) {
1307 for (ndig=0; ndig<fInput->NDigits(cath); ndig++) {
1308 dig = fInput->Digit(cath, ndig);
1311 if (fHitMap[cath]->TestHit(i,j)==kUsed ||fHitMap[0]->TestHit(i,j)==kEmpty) {
1315 fprintf(stderr,"\n CATHODE %d CLUSTER %d\n",cath,ncls);
1316 AliMUONRawCluster c;
1317 c.fMultiplicity[0]=0;
1318 c.fMultiplicity[1]=0;
1319 c.fPeakSignal[cath]=dig->fSignal;
1320 c.fTracks[0]=dig->fHit;
1321 c.fTracks[1]=dig->fTracks[0];
1322 c.fTracks[2]=dig->fTracks[1];
1323 // tag the beginning of cluster list in a raw cluster
1326 fSeg[cath]->GetPadC(i,j,xcu, ycu, fZPlane);
1327 fSector= fSeg[cath]->Sector(i,j)/100;
1328 // printf("\n New Seed %d %d ", i,j);
1330 FindCluster(i,j,cath,c);
1331 // ^^^^^^^^^^^^^^^^^^^^^^^^
1332 // center of gravity
1334 c.fX[0]=fSeg[0]->GetAnod(c.fX[0]);
1337 c.fX[1]=fSeg[0]->GetAnod(c.fX[1]);
1339 fprintf(stderr,"\n Cathode 1 multiplicite %d X(CG) %f Y(CG) %f\n",
1340 c.fMultiplicity[0],c.fX[0],c.fY[0]);
1341 fprintf(stderr," Cathode 2 multiplicite %d X(CG) %f Y(CG) %f\n",
1342 c.fMultiplicity[1],c.fX[1],c.fY[1]);
1344 // Analyse cluster and decluster if necessary
1347 c.fNcluster[1]=fNRawClusters;
1348 c.fClusterType=c.PhysicsContribution();
1355 // reset Cluster object
1356 { // begin local scope
1357 for (int k=0;k<c.fMultiplicity[0];k++) c.fIndexMap[k][0]=0;
1358 } // end local scope
1360 { // begin local scope
1361 for (int k=0;k<c.fMultiplicity[1];k++) c.fIndexMap[k][1]=0;
1362 } // end local scope
1364 c.fMultiplicity[0]=c.fMultiplicity[0]=0;
1368 } // end loop cathodes
1373 Float_t AliMUONClusterFinderVS::SingleMathiesonFit(AliMUONRawCluster *c, Int_t cath)
1375 // Performs a single Mathieson fit on one cathode
1377 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1379 clusterInput.Fitter()->SetFCN(fcnS1);
1380 clusterInput.Fitter()->mninit(2,10,7);
1381 Double_t arglist[20];
1384 // Set starting values
1385 static Double_t vstart[2];
1390 // lower and upper limits
1391 static Double_t lower[2], upper[2];
1393 fSeg[cath]->GetPadI(c->fX[cath], c->fY[cath], fZPlane, ix, iy);
1394 Int_t isec=fSeg[cath]->Sector(ix, iy);
1395 lower[0]=vstart[0]-fSeg[cath]->Dpx(isec)/2;
1396 lower[1]=vstart[1]-fSeg[cath]->Dpy(isec)/2;
1398 upper[0]=lower[0]+fSeg[cath]->Dpx(isec);
1399 upper[1]=lower[1]+fSeg[cath]->Dpy(isec);
1402 static Double_t step[2]={0.0005, 0.0005};
1404 clusterInput.Fitter()->mnparm(0,"x1",vstart[0],step[0],lower[0],upper[0],ierflag);
1405 clusterInput.Fitter()->mnparm(1,"y1",vstart[1],step[1],lower[1],upper[1],ierflag);
1406 // ready for minimisation
1407 clusterInput.Fitter()->SetPrintLevel(1);
1408 clusterInput.Fitter()->mnexcm("SET OUT", arglist, 0, ierflag);
1412 clusterInput.Fitter()->mnexcm("SET NOGR", arglist, 0, ierflag);
1413 clusterInput.Fitter()->mnexcm("MIGRAD", arglist, 0, ierflag);
1414 clusterInput.Fitter()->mnexcm("EXIT" , arglist, 0, ierflag);
1415 Double_t fmin, fedm, errdef;
1416 Int_t npari, nparx, istat;
1418 clusterInput.Fitter()->mnstat(fmin, fedm, errdef, npari, nparx, istat);
1422 // Get fitted parameters
1423 Double_t xrec, yrec;
1425 Double_t epxz, b1, b2;
1427 clusterInput.Fitter()->mnpout(0, chname, xrec, epxz, b1, b2, ierflg);
1428 clusterInput.Fitter()->mnpout(1, chname, yrec, epxz, b1, b2, ierflg);
1434 Float_t AliMUONClusterFinderVS::CombiSingleMathiesonFit(AliMUONRawCluster *c)
1436 // Perform combined Mathieson fit on both cathode planes
1438 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1439 clusterInput.Fitter()->SetFCN(fcnCombiS1);
1440 clusterInput.Fitter()->mninit(2,10,7);
1441 Double_t arglist[20];
1444 static Double_t vstart[2];
1445 vstart[0]=fXInit[0];
1446 vstart[1]=fYInit[0];
1449 // lower and upper limits
1450 static Float_t lower[2], upper[2];
1452 fSeg[0]->GetPadI(fXInit[0], fYInit[0], fZPlane, ix, iy);
1453 isec=fSeg[0]->Sector(ix, iy);
1454 Float_t dpy=fSeg[0]->Dpy(isec);
1455 fSeg[1]->GetPadI(fXInit[0], fYInit[0], fZPlane, ix, iy);
1456 isec=fSeg[1]->Sector(ix, iy);
1457 Float_t dpx=fSeg[1]->Dpx(isec);
1460 Float_t xdum, ydum, zdum;
1462 // Find save upper and lower limits
1466 for (fSeg[1]->FirstPad(fXInit[0], fYInit[0], fZPlane, dpx, 0.);
1467 fSeg[1]->MorePads(); fSeg[1]->NextPad())
1469 ix=fSeg[1]->Ix(); iy=fSeg[1]->Iy();
1470 fSeg[1]->GetPadC(ix,iy, upper[0], ydum, zdum);
1471 if (icount ==0) lower[0]=upper[0];
1475 if (lower[0]>upper[0]) {xdum=lower[0]; lower[0]=upper[0]; upper[0]=xdum;}
1479 for (fSeg[0]->FirstPad(fXInit[0], fYInit[0], fZPlane, 0., dpy);
1480 fSeg[0]->MorePads(); fSeg[0]->NextPad())
1482 ix=fSeg[0]->Ix(); iy=fSeg[0]->Iy();
1483 fSeg[0]->GetPadC(ix,iy,xdum,upper[1],zdum);
1484 if (icount ==0) lower[1]=upper[1];
1488 if (lower[1]>upper[1]) {xdum=lower[1]; lower[1]=upper[1]; upper[1]=xdum;}
1491 static Double_t step[2]={0.00001, 0.0001};
1493 clusterInput.Fitter()->mnparm(0,"x1",vstart[0],step[0],lower[0],upper[0],ierflag);
1494 clusterInput.Fitter()->mnparm(1,"y1",vstart[1],step[1],lower[1],upper[1],ierflag);
1495 // ready for minimisation
1496 clusterInput.Fitter()->SetPrintLevel(1);
1497 clusterInput.Fitter()->mnexcm("SET OUT", arglist, 0, ierflag);
1501 clusterInput.Fitter()->mnexcm("SET NOGR", arglist, 0, ierflag);
1502 clusterInput.Fitter()->mnexcm("MIGRAD", arglist, 0, ierflag);
1503 clusterInput.Fitter()->mnexcm("EXIT" , arglist, 0, ierflag);
1504 Double_t fmin, fedm, errdef;
1505 Int_t npari, nparx, istat;
1507 clusterInput.Fitter()->mnstat(fmin, fedm, errdef, npari, nparx, istat);
1511 // Get fitted parameters
1512 Double_t xrec, yrec;
1514 Double_t epxz, b1, b2;
1516 clusterInput.Fitter()->mnpout(0, chname, xrec, epxz, b1, b2, ierflg);
1517 clusterInput.Fitter()->mnpout(1, chname, yrec, epxz, b1, b2, ierflg);
1523 Bool_t AliMUONClusterFinderVS::DoubleMathiesonFit(AliMUONRawCluster *c, Int_t cath)
1525 // Performs a double Mathieson fit on one cathode
1529 // Initialise global variables for fit
1530 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1531 clusterInput.Fitter()->SetFCN(fcnS2);
1532 clusterInput.Fitter()->mninit(5,10,7);
1533 Double_t arglist[20];
1536 // Set starting values
1537 static Double_t vstart[5];
1538 vstart[0]=fX[fIndLocal[0][cath]][cath];
1539 vstart[1]=fY[fIndLocal[0][cath]][cath];
1540 vstart[2]=fX[fIndLocal[1][cath]][cath];
1541 vstart[3]=fY[fIndLocal[1][cath]][cath];
1542 vstart[4]=Float_t(fQ[fIndLocal[0][cath]][cath])/
1543 Float_t(fQ[fIndLocal[0][cath]][cath]+fQ[fIndLocal[1][cath]][cath]);
1544 // lower and upper limits
1545 static Float_t lower[5], upper[5];
1546 Int_t isec=fSeg[cath]->Sector(fIx[fIndLocal[0][cath]][cath], fIy[fIndLocal[0][cath]][cath]);
1547 lower[0]=vstart[0]-fSeg[cath]->Dpx(isec);
1548 lower[1]=vstart[1]-fSeg[cath]->Dpy(isec);
1550 upper[0]=lower[0]+2.*fSeg[cath]->Dpx(isec);
1551 upper[1]=lower[1]+2.*fSeg[cath]->Dpy(isec);
1553 isec=fSeg[cath]->Sector(fIx[fIndLocal[1][cath]][cath], fIy[fIndLocal[1][cath]][cath]);
1554 lower[2]=vstart[2]-fSeg[cath]->Dpx(isec)/2;
1555 lower[3]=vstart[3]-fSeg[cath]->Dpy(isec)/2;
1557 upper[2]=lower[2]+fSeg[cath]->Dpx(isec);
1558 upper[3]=lower[3]+fSeg[cath]->Dpy(isec);
1563 static Double_t step[5]={0.0005, 0.0005, 0.0005, 0.0005, 0.0001};
1565 clusterInput.Fitter()->mnparm(0,"x1",vstart[0],step[0],lower[0],upper[0],ierflag);
1566 clusterInput.Fitter()->mnparm(1,"y1",vstart[1],step[1],lower[1],upper[1],ierflag);
1567 clusterInput.Fitter()->mnparm(2,"x2",vstart[2],step[2],lower[2],upper[2],ierflag);
1568 clusterInput.Fitter()->mnparm(3,"y2",vstart[3],step[3],lower[3],upper[3],ierflag);
1569 clusterInput.Fitter()->mnparm(4,"a0",vstart[4],step[4],lower[4],upper[4],ierflag);
1570 // ready for minimisation
1571 clusterInput.Fitter()->SetPrintLevel(-1);
1572 clusterInput.Fitter()->mnexcm("SET OUT", arglist, 0, ierflag);
1576 clusterInput.Fitter()->mnexcm("SET NOGR", arglist, 0, ierflag);
1577 clusterInput.Fitter()->mnexcm("MIGRAD", arglist, 0, ierflag);
1578 clusterInput.Fitter()->mnexcm("EXIT" , arglist, 0, ierflag);
1579 // Get fitted parameters
1580 Double_t xrec[2], yrec[2], qfrac;
1582 Double_t epxz, b1, b2;
1584 clusterInput.Fitter()->mnpout(0, chname, xrec[0], epxz, b1, b2, ierflg);
1585 clusterInput.Fitter()->mnpout(1, chname, yrec[0], epxz, b1, b2, ierflg);
1586 clusterInput.Fitter()->mnpout(2, chname, xrec[1], epxz, b1, b2, ierflg);
1587 clusterInput.Fitter()->mnpout(3, chname, yrec[1], epxz, b1, b2, ierflg);
1588 clusterInput.Fitter()->mnpout(4, chname, qfrac, epxz, b1, b2, ierflg);
1590 Double_t fmin, fedm, errdef;
1591 Int_t npari, nparx, istat;
1593 clusterInput.Fitter()->mnstat(fmin, fedm, errdef, npari, nparx, istat);
1598 Float_t AliMUONClusterFinderVS::CombiDoubleMathiesonFit(AliMUONRawCluster *c)
1601 // Perform combined double Mathieson fit on both cathode planes
1603 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1604 clusterInput.Fitter()->SetFCN(fcnCombiS2);
1605 clusterInput.Fitter()->mninit(6,10,7);
1606 Double_t arglist[20];
1609 // Set starting values
1610 static Double_t vstart[6];
1611 vstart[0]=fXInit[0];
1612 vstart[1]=fYInit[0];
1613 vstart[2]=fXInit[1];
1614 vstart[3]=fYInit[1];
1615 vstart[4]=fQrInit[0];
1616 vstart[5]=fQrInit[1];
1617 // lower and upper limits
1618 static Float_t lower[6], upper[6];
1622 fSeg[1]->GetPadI(fXInit[0], fYInit[0], fZPlane, ix, iy);
1623 isec=fSeg[1]->Sector(ix, iy);
1624 dpx=fSeg[1]->Dpx(isec);
1626 fSeg[0]->GetPadI(fXInit[0], fYInit[0], fZPlane, ix, iy);
1627 isec=fSeg[0]->Sector(ix, iy);
1628 dpy=fSeg[0]->Dpy(isec);
1632 Float_t xdum, ydum, zdum;
1633 // printf("\n Cluster Finder: %f %f %f %f ", fXInit[0], fXInit[1],fYInit[0], fYInit[1] );
1635 // Find save upper and lower limits
1638 for (fSeg[1]->FirstPad(fXInit[0], fYInit[0], fZPlane, dpx, 0.);
1639 fSeg[1]->MorePads(); fSeg[1]->NextPad())
1641 ix=fSeg[1]->Ix(); iy=fSeg[1]->Iy();
1642 fSeg[1]->GetPadC(ix,iy,upper[0],ydum,zdum);
1643 if (icount ==0) lower[0]=upper[0];
1646 if (lower[0]>upper[0]) {xdum=lower[0]; lower[0]=upper[0]; upper[0]=xdum;}
1649 for (fSeg[0]->FirstPad(fXInit[0], fYInit[0], fZPlane, 0., dpy);
1650 fSeg[0]->MorePads(); fSeg[0]->NextPad())
1652 ix=fSeg[0]->Ix(); iy=fSeg[0]->Iy();
1653 fSeg[0]->GetPadC(ix,iy,xdum,upper[1],zdum);
1654 if (icount ==0) lower[1]=upper[1];
1657 if (lower[1]>upper[1]) {xdum=lower[1]; lower[1]=upper[1]; upper[1]=xdum;}
1659 fSeg[1]->GetPadI(fXInit[1], fYInit[1], fZPlane, ix, iy);
1660 isec=fSeg[1]->Sector(ix, iy);
1661 dpx=fSeg[1]->Dpx(isec);
1662 fSeg[0]->GetPadI(fXInit[1], fYInit[1], fZPlane, ix, iy);
1663 isec=fSeg[0]->Sector(ix, iy);
1664 dpy=fSeg[0]->Dpy(isec);
1667 // Find save upper and lower limits
1671 for (fSeg[1]->FirstPad(fXInit[1], fYInit[1], fZPlane, dpx, 0);
1672 fSeg[1]->MorePads(); fSeg[1]->NextPad())
1674 ix=fSeg[1]->Ix(); iy=fSeg[1]->Iy();
1675 fSeg[1]->GetPadC(ix,iy,upper[2],ydum,zdum);
1676 if (icount ==0) lower[2]=upper[2];
1679 if (lower[2]>upper[2]) {xdum=lower[2]; lower[2]=upper[2]; upper[2]=xdum;}
1683 for (fSeg[0]->FirstPad(fXInit[1], fYInit[1], fZPlane, 0, dpy);
1684 fSeg[0]-> MorePads(); fSeg[0]->NextPad())
1686 ix=fSeg[0]->Ix(); iy=fSeg[0]->Iy();
1687 fSeg[0]->GetPadC(ix,iy,xdum,upper[3],zdum);
1688 if (icount ==0) lower[3]=upper[3];
1691 if (lower[3]>upper[3]) {xdum=lower[3]; lower[3]=upper[3]; upper[3]=xdum;}
1699 static Double_t step[6]={0.0005, 0.0005, 0.0005, 0.0005, 0.001, 0.001};
1700 clusterInput.Fitter()->mnparm(0,"x1",vstart[0],step[0],lower[0],upper[0],ierflag);
1701 clusterInput.Fitter()->mnparm(1,"y1",vstart[1],step[1],lower[1],upper[1],ierflag);
1702 clusterInput.Fitter()->mnparm(2,"x2",vstart[2],step[2],lower[2],upper[2],ierflag);
1703 clusterInput.Fitter()->mnparm(3,"y2",vstart[3],step[3],lower[3],upper[3],ierflag);
1704 clusterInput.Fitter()->mnparm(4,"a0",vstart[4],step[4],lower[4],upper[4],ierflag);
1705 clusterInput.Fitter()->mnparm(5,"a1",vstart[5],step[5],lower[5],upper[5],ierflag);
1706 // ready for minimisation
1707 clusterInput.Fitter()->SetPrintLevel(-1);
1708 clusterInput.Fitter()->mnexcm("SET OUT", arglist, 0, ierflag);
1712 clusterInput.Fitter()->mnexcm("SET NOGR", arglist, 0, ierflag);
1713 clusterInput.Fitter()->mnexcm("MIGRAD", arglist, 0, ierflag);
1714 clusterInput.Fitter()->mnexcm("EXIT" , arglist, 0, ierflag);
1715 // Get fitted parameters
1717 Double_t epxz, b1, b2;
1719 clusterInput.Fitter()->mnpout(0, chname, fXFit[0], epxz, b1, b2, ierflg);
1720 clusterInput.Fitter()->mnpout(1, chname, fYFit[0], epxz, b1, b2, ierflg);
1721 clusterInput.Fitter()->mnpout(2, chname, fXFit[1], epxz, b1, b2, ierflg);
1722 clusterInput.Fitter()->mnpout(3, chname, fYFit[1], epxz, b1, b2, ierflg);
1723 clusterInput.Fitter()->mnpout(4, chname, fQrFit[0], epxz, b1, b2, ierflg);
1724 clusterInput.Fitter()->mnpout(5, chname, fQrFit[1], epxz, b1, b2, ierflg);
1726 Double_t fmin, fedm, errdef;
1727 Int_t npari, nparx, istat;
1729 clusterInput.Fitter()->mnstat(fmin, fedm, errdef, npari, nparx, istat);
1737 void AliMUONClusterFinderVS::Split(AliMUONRawCluster* c)
1740 // One cluster for each maximum
1743 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1744 for (j=0; j<2; j++) {
1745 AliMUONRawCluster cnew;
1746 for (cath=0; cath<2; cath++) {
1747 cnew.fChi2[cath]=fChi2[0];
1750 cnew.fNcluster[0]=-1;
1751 cnew.fNcluster[1]=fNRawClusters;
1753 cnew.fNcluster[0]=fNPeaks;
1754 cnew.fNcluster[1]=0;
1756 cnew.fMultiplicity[cath]=0;
1757 cnew.fX[cath]=Float_t(fXFit[j]);
1758 cnew.fY[cath]=Float_t(fYFit[j]);
1760 cnew.fQ[cath]=Int_t(clusterInput.TotalCharge(cath)*fQrFit[cath]);
1762 cnew.fQ[cath]=Int_t(clusterInput.TotalCharge(cath)*(1-fQrFit[cath]));
1764 fSeg[cath]->SetHit(fXFit[j],fYFit[j],fZPlane);
1765 for (i=0; i<fMul[cath]; i++) {
1766 cnew.fIndexMap[cnew.fMultiplicity[cath]][cath]=
1767 c->fIndexMap[i][cath];
1768 fSeg[cath]->SetPad(fIx[i][cath], fIy[i][cath]);
1769 Float_t q1=fInput->Response()->IntXY(fSeg[cath]);
1770 cnew.fContMap[i][cath]
1771 =(q1*Float_t(cnew.fQ[cath]))/Float_t(fQ[i][cath]);
1772 cnew.fMultiplicity[cath]++;
1774 FillCluster(&cnew,0,cath);
1777 cnew.fClusterType=cnew.PhysicsContribution();
1778 if (cnew.fQ[0]>0 && cnew.fQ[1]>0) AddRawCluster(cnew);
1785 // Minimisation functions
1787 void fcnS1(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
1789 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1796 for (i=0; i<clusterInput.Nmul(0); i++) {
1797 Float_t q0=clusterInput.Charge(i,0);
1798 Float_t q1=clusterInput.DiscrChargeS1(i,par);
1807 void fcnCombiS1(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
1809 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1816 for (cath=0; cath<2; cath++) {
1817 for (i=0; i<clusterInput.Nmul(cath); i++) {
1818 Float_t q0=clusterInput.Charge(i,cath);
1819 Float_t q1=clusterInput.DiscrChargeCombiS1(i,par,cath);
1830 void fcnS2(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
1832 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1839 for (i=0; i<clusterInput.Nmul(0); i++) {
1841 Float_t q0=clusterInput.Charge(i,0);
1842 Float_t q1=clusterInput.DiscrChargeS2(i,par);
1852 void fcnCombiS2(Int_t &npar, Double_t *gin, Double_t &f, Double_t *par, Int_t iflag)
1854 AliMUONClusterInput& clusterInput = *(AliMUONClusterInput::Instance());
1860 for (cath=0; cath<2; cath++) {
1861 for (i=0; i<clusterInput.Nmul(cath); i++) {
1862 Float_t q0=clusterInput.Charge(i,cath);
1863 Float_t q1=clusterInput.DiscrChargeCombiS2(i,par,cath);
1873 void AliMUONClusterFinderVS::AddRawCluster(const AliMUONRawCluster c)
1876 // Add a raw cluster copy to the list
1878 AliMUON *pMUON=(AliMUON*)gAlice->GetModule("MUON");
1879 pMUON->AddRawCluster(fInput->Chamber(),c);
1881 fprintf(stderr,"\nfNRawClusters %d\n",fNRawClusters);
1884 Bool_t AliMUONClusterFinderVS::TestTrack(Int_t t) {
1885 if (fTrack[0]==-1 || fTrack[1]==-1) {
1887 } else if (t==fTrack[0] || t==fTrack[1]) {
1894 AliMUONClusterFinderVS& AliMUONClusterFinderVS
1895 ::operator = (const AliMUONClusterFinderVS& rhs)
1897 // Dummy assignment operator