Correct character constantness
[u/mrichter/AliRoot.git] / MUON / AliMUONSurveyObj.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
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  **************************************************************************/
15
16 //-----------------------------------------------------------------------------
17 /// \class AliMUONSurveyObj
18 /// Base class for the survey processing of the ALICE DiMuon spectrometer 
19 ///
20 /// This base object provides methods to process the survey+photogrammetry
21 /// data of the Chambers (frames) and Detection Elements of the DiMuon
22 /// Spectrometer and calculate their misalignments. 
23 ///
24 /// \author Javier Castillo
25 //-----------------------------------------------------------------------------
26
27 #include <fstream>
28
29 #include "TMath.h"
30 #include "TVector3.h"
31 #include "TGeoMatrix.h"
32 #include "TFitter.h"
33 #include "TMinuit.h"
34 #include "TString.h"
35 #include "TH2.h"
36 #include "TF2.h"
37 #include "TGraph2DErrors.h"
38 #include "TArrayD.h"
39
40 #include "AliLog.h"
41 #include "AliSurveyPoint.h"
42
43 #include "AliMUONSurveyObj.h"
44 #include "AliMUONSurveyUtil.h"
45
46 void SurveyFcn(int &npar, double *g, double &f, double *par, int iflag);
47
48 /// \cond CLASSIMP
49 ClassImp(AliMUONSurveyObj)
50 /// \endcond
51
52 AliMUONSurveyObj::AliMUONSurveyObj() 
53   : TObject() 
54   , fSTargets(0x0)
55   , fGBTargets(0x0)
56   , fLBTargets(0x0)
57   , fLocalTrf(0x0)
58   , fAlignTrf(0x0)
59   , fBaseTrf(0x0)
60   , fOwnerLocalTrf(kFALSE)
61   , fOwnerAlignTrf(kTRUE)
62   , fOwnerBaseTrf(kFALSE)
63   , fPlane(0x0)
64   , fFitter(0x0)
65   , fXMin(-4000.)
66   , fXMax(4000.)
67   , fYMin(-4000.)
68   , fYMax(4000.)
69   , fZMin(-20000.)
70   , fZMax(20000.)
71 {
72 /// Default constructor
73
74   fSTargets = new TObjArray();  
75   fSTargets->SetOwner(kFALSE);
76   fGBTargets = new TObjArray();  
77   fGBTargets->SetOwner(kFALSE);
78   fLBTargets = new TObjArray();  
79   fLBTargets->SetOwner(kFALSE);  
80
81   fAlignTrf = new TGeoCombiTrans();
82
83   fFitter = new TFitter(100);
84 }
85
86 AliMUONSurveyObj::~AliMUONSurveyObj() {
87   /// Destructor
88   if(fSTargets) {
89     fSTargets->Delete();
90     fSTargets = 0x0;
91   }
92   if(fGBTargets) {
93     fGBTargets->Delete();
94     fGBTargets = 0x0;
95   }
96   if(fLBTargets) {
97     fLBTargets->Delete();
98     fLBTargets = 0x0;
99   }
100   if (fPlane) {
101     fPlane->Delete();
102     fPlane = 0x0;
103   }
104   if(fOwnerLocalTrf && fLocalTrf) {
105     fLocalTrf->Delete();
106     fLocalTrf = 0x0;
107   }
108   if(fOwnerAlignTrf && fAlignTrf) {
109     fAlignTrf->Delete();
110     fAlignTrf = 0x0;
111   }
112   if(fOwnerBaseTrf && fBaseTrf) {
113     fBaseTrf->Delete();
114     fBaseTrf = 0x0;
115   }
116   if (fFitter){
117     fFitter->Delete();
118     fFitter = 0x0;
119   }
120 }
121
122 void AliMUONSurveyObj::AddStickerTarget(AliSurveyPoint *stPoint){
123   fSTargets->Add(stPoint);
124 }
125
126 void AliMUONSurveyObj::AddGButtonTarget(AliSurveyPoint *btPoint){
127   fGBTargets->Add(btPoint);
128 }
129
130 void AliMUONSurveyObj::AddLButtonTarget(AliSurveyPoint *btPoint){
131   fLBTargets->Add(btPoint);
132 }
133
134 void AliMUONSurveyObj::AddLButtonTarget(TVector3 *btVector){
135   fLBTargets->Add(btVector);
136 }
137
138 Int_t AliMUONSurveyObj::AddStickerTargets(TObjArray *pArray, TString stBaseName, Int_t lTargetMax){
139   if (!pArray) {
140     AliError(Form("Survey points array is empty %p!",pArray));
141     return 0;
142   }
143   if (stBaseName.IsNull()) {
144     AliError(Form("Need base name for sticker targets %s!",stBaseName.Data()));
145     return 0;
146   }
147   
148   Int_t stIndex = 0;
149   AliSurveyPoint *pointSST = 0x0;
150
151   TString stNumber;
152   
153   for (int iPoint=0; iPoint<lTargetMax; iPoint++) {
154     TString stFullName(stBaseName);
155     stNumber = Form("%d",iPoint+1);
156     if(lTargetMax>9&&iPoint+1<10) {
157       stFullName+="0";
158     }
159     stFullName+=stNumber;
160
161     pointSST = (AliSurveyPoint *)pArray->FindObject(stFullName.Data());
162
163     if(pointSST) {
164       AddStickerTarget(pointSST);
165       AliInfo(Form("Added survey sticker target %s at index %d",pointSST->GetName(),stIndex));
166       stIndex++;
167     }
168   }
169
170   AliInfo(Form("Found %d sticker targets with base name %s",fSTargets->GetEntries(),stBaseName.Data()));
171   return stIndex;
172 }
173
174 Int_t AliMUONSurveyObj::AddGButtonTargets(TObjArray *pArray, TString btBaseName, Int_t lTargetMax){
175   printf("%s \n",btBaseName.Data());
176   if (!pArray) {
177     AliError(Form("Survey points array is empty %p!",pArray));
178     return 0;
179   }
180   if (btBaseName.IsNull()) {
181     AliError(Form("Need base name for button targets %s!",btBaseName.Data()));
182     return 0;
183   }
184   
185   Int_t btIndex = 0;
186   AliSurveyPoint *pointSBT = 0x0;
187
188   TString btNumber;
189   
190   for (int iPoint=0; iPoint<lTargetMax; iPoint++) {
191     TString btFullName(btBaseName);
192     btNumber = Form("%d",iPoint+1);
193     if(lTargetMax>9&&iPoint+1<10) {
194       btFullName+="0";
195     }
196     btFullName+=btNumber;
197     printf("%s \n",btFullName.Data());
198     pointSBT = (AliSurveyPoint *)pArray->FindObject(btFullName.Data());
199
200     if(pointSBT) {
201       AddGButtonTarget(pointSBT);
202       AliInfo(Form("Added survey button target %s at index %d",pointSBT->GetName(),btIndex));
203       btIndex++;
204     }
205   }
206
207   AliInfo(Form("Found %d button targets with base name %s",fGBTargets->GetEntries(),btBaseName.Data()));
208   return btIndex;
209 }
210
211 Int_t AliMUONSurveyObj::AddLButtonTargets(TObjArray *pArray, TString btBaseName, Int_t lTargetMax){
212   printf("%s \n",btBaseName.Data());
213   if (!pArray) {
214     AliError(Form("Local points array is empty %p!",pArray));
215     return 0;
216   }
217   if (btBaseName.IsNull()) {
218     AliError(Form("Need base name for button targets %s!",btBaseName.Data()));
219     return 0;
220   }
221   
222   Int_t btIndex = 0;
223   AliSurveyPoint *pointSBT = 0x0;
224
225   TString btNumber;
226   
227   for (int iPoint=0; iPoint<lTargetMax; iPoint++) {
228     TString btFullName(btBaseName);
229     btNumber = Form("%d",iPoint+1);
230     if(lTargetMax>9&&iPoint+1<10) {
231       btFullName+="0";
232     }
233     btFullName+=btNumber;
234     printf("%s \n",btFullName.Data());
235     pointSBT = (AliSurveyPoint *)pArray->FindObject(btFullName.Data());
236
237     if(pointSBT) {
238       AddLButtonTarget(pointSBT);
239       AliInfo(Form("Added local button target %s at index %d",pointSBT->GetName(),btIndex));
240       btIndex++;
241     }
242   }
243
244   AliInfo(Form("Found %d local button targets with base name %s",fLBTargets->GetEntries(),btBaseName.Data()));
245   return btIndex;
246 }
247
248 Int_t AliMUONSurveyObj::GetNStickerTargets() {
249   return fSTargets->GetEntriesFast();
250 }
251
252 AliSurveyPoint* AliMUONSurveyObj::GetStickerTarget(Int_t stIndex){
253   if (stIndex<0||stIndex>=fSTargets->GetEntriesFast()) {
254     AliError(Form("No sticker target at index %d",stIndex));
255     return 0x0;
256   }
257   else {
258     return (AliSurveyPoint*)fSTargets->At(stIndex);
259   }
260 }
261
262 Int_t AliMUONSurveyObj::GetNGButtonTargets() {
263   return fGBTargets->GetEntriesFast();
264 }
265
266 AliSurveyPoint* AliMUONSurveyObj::GetGButtonTarget(Int_t btIndex){
267   if (btIndex<0||btIndex>=fGBTargets->GetEntriesFast()) {
268     AliError(Form("No surveyed button target at index %d",btIndex));
269     return 0x0;
270   }
271   else {
272     return (AliSurveyPoint*)fGBTargets->At(btIndex);
273   }
274 }
275
276 Int_t AliMUONSurveyObj::GetNLButtonTargets() {
277   return fGBTargets->GetEntriesFast();
278 }
279
280 AliSurveyPoint* AliMUONSurveyObj::GetLButtonTarget(Int_t btIndex){
281   if (btIndex<0||btIndex>=fLBTargets->GetEntriesFast()) {
282     AliError(Form("No surveyed button target at index %d",btIndex));
283     return 0x0;
284   }
285   else {
286     if(fLBTargets->At(btIndex)->IsA()==TVector3::Class()){
287       TVector3 *lBT = (TVector3*)fLBTargets->At(btIndex);
288       TString str("B");
289       return (new AliSurveyPoint(TString("local"),(float)lBT->X(),(float)lBT->Y(),(float)lBT->Z(),(float)0.,(float)0.,(float)0.,'B',kTRUE));
290     } else if(fLBTargets->At(btIndex)->IsA()==AliSurveyPoint::Class()) {
291       AliSurveyPoint *lBT = (AliSurveyPoint*)fLBTargets->At(btIndex);
292       return lBT;
293     } else {
294       AliError(Form("Unexpected class %s ! Valid classes are TVector3 or AliSurveyPoint",fLBTargets->At(btIndex)->ClassName()));
295       return 0;
296     }
297   }
298 }
299
300 void AliMUONSurveyObj::SetPlane(TString pName, Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax){
301   if(fPlane) {
302     fPlane->Delete();
303     fPlane = 0x0;
304   }
305   fPlane = new TF2(pName,this,&AliMUONSurveyObj::eqPlane,xMin,xMax,yMin,yMax,3,"AliMUONSurveyObj","eqPlane");
306 }
307
308 void AliMUONSurveyObj::SetPlaneParameters(Double_t p0, Double_t p1, Double_t p2) {
309   if (!fPlane) {
310     AliError("Must use SetPlane before SetPlaneParameters!!!");
311   }
312   else {
313     fPlane->SetParameter(0,p0);
314     fPlane->SetParameter(1,p1);
315     fPlane->SetParameter(2,p2);
316   }
317 }
318
319 void AliMUONSurveyObj::DrawSTargets() {
320     
321   TGraph2DErrors *gST = new TGraph2DErrors(3);
322   AliSurveyPoint *pST = 0x0;
323   for (Int_t iPoint=0; iPoint<GetNStickerTargets(); iPoint++) {
324     pST = GetStickerTarget(iPoint);
325     //    pST->PrintPoint();
326     gST->SetPoint(iPoint,pST->GetX(),pST->GetY(),pST->GetZ());
327     gST->SetPointError(iPoint,pST->GetPrecisionX(),pST->GetPrecisionY(),pST->GetPrecisionZ());
328   }
329   gST->DrawClone("P0");
330
331   if (gST) gST->Delete();
332 }
333
334 Double_t AliMUONSurveyObj::FitPlane() {
335   if (!fPlane) {
336     AliError("Must use SetPlane before FitPlane!!!");
337     return 0.;
338   }
339   if (fSTargets->GetEntriesFast()<3) {
340     AliError("Not enough sticker targets (%d) for plane fitting!!!");
341     return 0.;
342   }
343
344   Double_t pl[3] = {0};
345   Double_t pg[3] = {0};
346     
347   TGraph2DErrors *gST = new TGraph2DErrors(3);
348   AliSurveyPoint *pST = 0x0;
349   for (Int_t iPoint=0; iPoint<GetNStickerTargets(); iPoint++) {
350     pST = GetStickerTarget(iPoint);
351     //    pST->PrintPoint();
352     pg[0] =  pST->GetX(); 
353     pg[1] =  pST->GetY(); 
354     pg[2] =  pST->GetZ(); 
355     fBaseTrf->MasterToLocal(pg,pl);
356     gST->SetPoint(iPoint,pl[0],pl[1],pl[2]);
357     printf("%d %f %f %f\n",iPoint,pl[0],pl[1],pl[2]);
358     gST->SetPointError(iPoint,pST->GetPrecisionX(),pST->GetPrecisionY(),pST->GetPrecisionZ());
359   }
360   gST->Fit(fPlane);
361
362   if (gST) gST->Delete();
363
364   return fPlane->GetChisquare();
365 }
366
367 Double_t AliMUONSurveyObj::SurveyChi2(Double_t *par){
368
369   TGeoTranslation transTemp;
370   TGeoRotation rotTemp;
371   TGeoCombiTrans trfTemp;
372
373   Double_t lChi2=0.;
374
375   trfTemp.SetTranslation(transTemp);
376   trfTemp.SetRotation(rotTemp);
377   trfTemp.Clear();
378   trfTemp.RotateZ(TMath::RadToDeg()*par[5]);
379   trfTemp.RotateY(TMath::RadToDeg()*par[4]);
380   trfTemp.RotateX(TMath::RadToDeg()*par[3]);
381   trfTemp.SetTranslation(par[0],par[1],par[2]);
382
383   TGeoHMatrix matGlo = (*fBaseTrf)*trfTemp;
384   TGeoCombiTrans trfGlo(matGlo);
385                 
386   Double_t pl[3] = {0};
387   Double_t pg[3] = {0};
388   
389   for(Int_t iPoint=0; iPoint<fGBTargets->GetEntries(); iPoint++){
390     AliSurveyPoint *gBT = (AliSurveyPoint*)fGBTargets->At(iPoint);
391     if(fLBTargets->At(iPoint)->IsA()==TVector3::Class()){
392       TVector3 *lBT = (TVector3*)fLBTargets->At(iPoint);
393       pl[0]=lBT->X();
394       pl[1]=lBT->Y();
395       pl[2]=lBT->Z();
396     } else if(fLBTargets->At(iPoint)->IsA()==AliSurveyPoint::Class()) {
397       AliSurveyPoint *lBT = (AliSurveyPoint*)fLBTargets->At(iPoint);
398       pl[0]=lBT->GetX();
399       pl[1]=lBT->GetY();
400       pl[2]=lBT->GetZ();
401     } else {
402       AliError(Form("Unexpected class %s ! Valid classes are TVector3 or AliSurveyPoint",fLBTargets->At(iPoint)->ClassName()));
403       return 0;
404     }
405
406     trfGlo.LocalToMaster(pl, pg);
407     //    printf("%d %f %f %f\n",iPoint,pg[0],pg[1],pg[2]);
408     if(fLBTargets->At(iPoint)->IsA()==TVector3::Class()){
409       lChi2 += (pg[0]-gBT->GetX())*(pg[0]-gBT->GetX())/(gBT->GetPrecisionX()*gBT->GetPrecisionX());
410       lChi2 += (pg[1]-gBT->GetY())*(pg[1]-gBT->GetY())/(gBT->GetPrecisionY()*gBT->GetPrecisionY());
411       lChi2 += (pg[2]-gBT->GetZ())*(pg[2]-gBT->GetZ())/(gBT->GetPrecisionZ()*gBT->GetPrecisionZ());
412     } else if(fLBTargets->At(iPoint)->IsA()==AliSurveyPoint::Class()) {
413       AliSurveyPoint *lBT = (AliSurveyPoint*)fLBTargets->At(iPoint);
414       lChi2 += (pg[0]-gBT->GetX())*(pg[0]-gBT->GetX())/(gBT->GetPrecisionX()*gBT->GetPrecisionX()+lBT->GetPrecisionX()*lBT->GetPrecisionX());
415       lChi2 += (pg[1]-gBT->GetY())*(pg[1]-gBT->GetY())/(gBT->GetPrecisionY()*gBT->GetPrecisionY()+lBT->GetPrecisionY()*lBT->GetPrecisionY());
416       lChi2 += (pg[2]-gBT->GetZ())*(pg[2]-gBT->GetZ())/(gBT->GetPrecisionZ()*gBT->GetPrecisionZ()+lBT->GetPrecisionZ()*lBT->GetPrecisionZ());
417     } else {
418       AliError(Form("Unexpected class %s ! Valid classes are TVector3 or AliSurveyPoint",fLBTargets->At(iPoint)->ClassName()));
419       return 0;
420     }
421   }
422
423   return lChi2;
424 }
425
426 //_____________________________________________________________________________
427 void SurveyFcn(int &npar, double *g, double &f, double *par, int iflag) {
428
429   // 
430   // Standard function as needed by Minuit-like minimization procedures. 
431   // For the set of parameters par calculates and returns chi-squared.
432   //
433
434   // smuggle a C++ object into a C function
435   AliMUONSurveyObj *aSurveyObj = (AliMUONSurveyObj*) gMinuit->GetObjectFit(); 
436
437   f = aSurveyObj->SurveyChi2(par);
438   if (iflag==3) {}
439   if (npar) {} 
440   if (g) {} // no warnings about unused stuff...
441
442 }
443
444 //_____________________________________________________________________________
445 Int_t AliMUONSurveyObj::SurveyToAlign(TGeoCombiTrans &quadTransf, Double_t *parErr, Double_t psi, Double_t tht, Double_t epsi, Double_t etht) {
446
447   if (fGBTargets->GetEntries()!=fLBTargets->GetEntries()){
448     AliError(Form("Different number of button targets: %d survey points and %d local coord!",
449                   fGBTargets->GetEntries(),fLBTargets->GetEntries()));
450     return 0;
451   }
452
453   TFitter fitter(100);
454   gMinuit->SetObjectFit(this);
455   fitter.SetFCN(SurveyFcn);
456   fitter.SetParameter(0,"dx",0,0.1,-20,20);
457   fitter.SetParameter(1,"dy",0,0.1,-20,20);
458   fitter.SetParameter(2,"dz",0,0.1,0,0);
459   fitter.SetParameter(3,"rx",psi,0.0001,-0.05,0.05);
460   fitter.SetParameter(4,"ry",tht,0.0001,-0.05,0.05);
461 //   fitter.SetParameter(3,"rx",psi,0.0001,psi-5*epsi,psi+5*epsi);
462 //   fitter.SetParameter(4,"ry",tht,0.0001,tht-5*etht,tht+5*etht);
463   fitter.SetParameter(5,"rz",0,0.0001,0,0);
464
465   if(psi) fitter.FixParameter(3);
466   if(tht) fitter.FixParameter(4);
467
468   double arglist[100];
469   arglist[0] = 2;
470   fitter.ExecuteCommand("SET PRINT", arglist, 1);
471   fitter.ExecuteCommand("SET ERR", arglist, 1);
472   arglist[0]=0;
473   //fitter.ExecuteCommand("SIMPLEX", arglist, 1);
474   //  fitter.ExecuteCommand("MINIMIZE", arglist, 1);
475   fitter.ExecuteCommand("MIGRAD", arglist, 1);
476   fitter.ExecuteCommand("IMPROVE", arglist, 1);
477   //  fitter.ExecuteCommand("MINOS", arglist, 1);
478   //  fitter.ExecuteCommand("CALL 3", arglist,0);
479
480   for (int j=0; j<3; j++) printf("%10.3f ",fitter.GetParameter(j));   
481   for (int j=3; j<6; j++) printf("%10.3f ",1000*fitter.GetParameter(j));   
482   printf("\n");
483   for (int j=0; j<3; j++) printf("%10.3f ",fitter.GetParError(j));
484   for (int j=3; j<6; j++) printf("%10.3f ",1000*fitter.GetParError(j));
485   printf("\n");
486
487   quadTransf.Clear();
488   quadTransf.RotateZ(TMath::RadToDeg()*fitter.GetParameter(5));
489   quadTransf.RotateY(TMath::RadToDeg()*fitter.GetParameter(4));
490   quadTransf.RotateX(TMath::RadToDeg()*fitter.GetParameter(3));
491   quadTransf.SetTranslation(fitter.GetParameter(0),fitter.GetParameter(1),fitter.GetParameter(2));
492
493   for(Int_t iPar=0; iPar<6; iPar++){
494     parErr[iPar] = fitter.GetParError(iPar);
495   }
496   if(epsi) parErr[3] = epsi;
497   if(etht) parErr[4] = etht;
498
499   return 1;
500
501 }
502
503 //_____________________________________________________________________________
504 Int_t AliMUONSurveyObj::SurveyToAlign(Double_t psi, Double_t tht, Double_t epsi, Double_t etht) {
505
506   if (fGBTargets->GetEntries()!=fLBTargets->GetEntries()){
507     AliError(Form("Different number of button targets: %d survey points and %d local coord!",
508                   fGBTargets->GetEntries(),fLBTargets->GetEntries()));
509     return 0;
510   }
511
512   //  TFitter fitter(100);
513   gMinuit->SetObjectFit(this);
514   fFitter->SetFCN(SurveyFcn);
515   fFitter->SetParameter(0,"dx",0,0.1,-20,20);
516   fFitter->SetParameter(1,"dy",0,0.1,-20,20);
517   fFitter->SetParameter(2,"dz",0,0.1,0,0);
518   if(psi)
519       fFitter->SetParameter(3,"rx",psi,epsi,psi-5*epsi,psi+5*epsi);
520   else
521     fFitter->SetParameter(3,"rx",psi,0.0001,-0.05,0.05);
522   if(tht)
523     fFitter->SetParameter(4,"ry",tht,etht,tht-5*etht,tht+5*etht);
524   else
525     fFitter->SetParameter(4,"ry",tht,0.0001,-0.05,0.05);
526 //   fFitter->SetParameter(3,"rx",psi,0.0001,psi-5*epsi,psi+5*epsi);
527 //   fFitter->SetParameter(4,"ry",tht,0.0001,tht-5*etht,tht+5*etht);
528   fFitter->SetParameter(5,"rz",0,0.0001,0,0);
529
530   if(psi) fFitter->FixParameter(3);
531   if(tht) fFitter->FixParameter(4);
532
533   double arglist[100];
534   arglist[0] = 2;
535   fFitter->ExecuteCommand("SET PRINT", arglist, 1);
536   fFitter->ExecuteCommand("SET ERR", arglist, 1);
537   arglist[0]=0;
538   //fFitter->ExecuteCommand("SIMPLEX", arglist, 1);
539   //  fFitter->ExecuteCommand("MINIMIZE", arglist, 1);
540   fFitter->ExecuteCommand("MIGRAD", arglist, 1);
541   fFitter->ExecuteCommand("IMPROVE", arglist, 1);
542 //   fFitter->ExecuteCommand("MINOS", arglist, 1);
543 //   fFitter->ExecuteCommand("CALL 3", arglist,0);
544
545   for (int j=0; j<3; j++) printf("%10.3f ",fFitter->GetParameter(j));   
546   for (int j=3; j<6; j++) printf("%10.3f ",1000*fFitter->GetParameter(j));   
547   printf("\n");
548   for (int j=0; j<3; j++) printf("%10.3f ",fFitter->GetParError(j));
549   for (int j=3; j<6; j++) printf("%10.3f ",1000*fFitter->GetParError(j));
550   printf("\n");
551
552   fAlignTrf->Clear();
553   fAlignTrf->RotateZ(TMath::RadToDeg()*fFitter->GetParameter(5));
554   fAlignTrf->RotateY(TMath::RadToDeg()*fFitter->GetParameter(4));
555   fAlignTrf->RotateX(TMath::RadToDeg()*fFitter->GetParameter(3));
556   fAlignTrf->SetTranslation(fFitter->GetParameter(0),fFitter->GetParameter(1),fFitter->GetParameter(2));
557
558   if(epsi) fFitter->ReleaseParameter(3); // To get error
559   if(etht) fFitter->ReleaseParameter(4); // To get error
560
561   TGeoCombiTrans lGlobalTrf = TGeoCombiTrans((*fBaseTrf)*(*fAlignTrf));
562   AliSurveyPoint *pointGBT;
563   AliSurveyPoint *pointLBT;
564   Double_t pl[3] = {0};
565   Double_t pg[3] = {0};
566   for (int iPoint=0; iPoint<GetNGButtonTargets(); iPoint++){
567     pointGBT=GetGButtonTarget(iPoint);
568     pointLBT=GetLButtonTarget(iPoint);
569     pl[0] = pointLBT->GetX();
570     pl[1] = pointLBT->GetY();
571     pl[2] = pointLBT->GetZ();
572     lGlobalTrf.LocalToMaster(pl,pg);
573     printf("Point %d  local: %.3f %.3f %.3f\n",iPoint,pl[0],pl[1],pl[2]);
574     printf("Point %d global: %.3f %.3f %.3f\n",iPoint,pg[0],pg[1],pg[2]);
575     printf("Point %d survey: %.3f %.3f %.3f\n",iPoint,pointGBT->GetX(),pointGBT->GetY(),pointGBT->GetZ());
576   }
577
578   return 1;
579
580 }
581
582 Double_t AliMUONSurveyObj::EvalFunction(TF2 *lFunction, Int_t iP1, Int_t iP2, const Char_t *lCoord) {
583
584   if (!lFunction) {
585     AliError("No function given!!!");
586     return 0;
587   }
588   AliSurveyPoint *gP1 = GetGButtonTarget(iP1);
589   AliSurveyPoint *gP2 = GetGButtonTarget(iP2);
590   
591   if(!gP1||!gP2){
592     AliError("Missing global button target!!!");
593     return 0;
594   }
595
596   //  AliInfo(Form("Function %s parameters %f %f %f %f %f %f",lFunction->GetName(),lFunction->GetParameter(0),lFunction->GetParameter(1),lFunction->GetParameter(2),lFunction->GetParameter(3),lFunction->GetParameter(4),lFunction->GetParameter(5)));
597   Double_t pl1[3] = {0};
598   Double_t pl2[3] = {0};
599   Double_t pg1[3] = {0};
600   Double_t pg2[3] = {0};
601     
602   pg1[0] =  gP1->GetX(); 
603   pg1[1] =  gP1->GetY(); 
604   pg1[2] =  gP1->GetZ(); 
605   pg2[0] =  gP2->GetX(); 
606   pg2[1] =  gP2->GetY(); 
607   pg2[2] =  gP2->GetZ(); 
608
609   fBaseTrf->MasterToLocal(pg1,pl1);
610   fBaseTrf->MasterToLocal(pg2,pl2);
611
612   Double_t lVal = 0.;
613   switch (lCoord[0]) {
614   case 'X':
615     {
616       lVal = lFunction->Eval(pl1[0],pl2[0]);
617       //      lVal = lFunction->Eval(gP1->GetX(),gP2->GetX());
618       //      AliInfo(Form("case X, lVal = %f",lVal));
619       return lVal;
620     }
621   case 'Y':
622     {
623       lVal = lFunction->Eval(pl1[1],pl2[1]);
624       //      lVal = lFunction->Eval(gP1->GetY(),gP2->GetY());
625       //      AliInfo(Form("case Y, lVal = %f",lVal));
626       return lVal;
627     }
628   case 'Z':
629     {
630       lVal = lFunction->Eval(pl1[2],pl2[2]);
631       //      lVal = lFunction->Eval(gP1->GetZ(),gP2->GetZ());
632       //      AliInfo(Form("case Z, lVal = %f",lVal));
633       return lVal;
634     }
635   default:
636     {
637       AliError(Form("Coordinate %c is not valid, options are X Y Z",lCoord));
638       return 0;
639     }
640   }
641 }
642
643 void AliMUONSurveyObj::CalculateTranslation(TF2 *xFunc, TF2 *yFunc, TF2 *zFunc, Int_t iP1, Int_t iP2, Double_t *lCenTemp) {
644
645   lCenTemp[0] = EvalFunction(xFunc,iP1,iP2,"X");
646   lCenTemp[1] = EvalFunction(yFunc,iP1,iP2,"Y");
647   lCenTemp[2] = EvalFunction(zFunc,iP1,iP2,"Z");
648
649 }
650
651 Double_t AliMUONSurveyObj::CalculateGlobalDiff(TGeoCombiTrans &lTransf, Int_t nPoints, TArrayD &lDiff){
652
653   if (nPoints > GetNGButtonTargets()) {
654     nPoints = GetNGButtonTargets();
655   }
656
657   for(Int_t iVal=0; iVal<nPoints*(3+1)+1; iVal++){
658     lDiff[iVal] = 0.;
659   }
660
661   Double_t pl[3] = {0};
662   Double_t pg[3] = {0};
663   Double_t pml[3] = {0};
664   Double_t pmg[3] = {0};
665   AliSurveyPoint *gBT = 0x0;
666   for(Int_t iPoint=0; iPoint<nPoints; iPoint++){
667     gBT = GetGButtonTarget(iPoint);
668     if(!gBT||!fLBTargets->At(iPoint)){
669       AliError(Form("The local or global target %d is missing!",iPoint));
670       lDiff[nPoints*(3+1)] = 1.e7;
671       return lDiff[nPoints*(3+1)];
672     }
673     if(fLBTargets->At(iPoint)->IsA()==TVector3::Class()){
674       TVector3 *lBT = (TVector3*)fLBTargets->At(iPoint);
675       pl[0]=lBT->X();
676       pl[1]=lBT->Y();
677       pl[2]=lBT->Z();
678     } else if(fLBTargets->At(iPoint)->IsA()==AliSurveyPoint::Class()) {
679       AliSurveyPoint *lBT = (AliSurveyPoint*)fLBTargets->At(iPoint);
680       pl[0]=lBT->GetX();
681       pl[1]=lBT->GetY();
682       pl[2]=lBT->GetZ();
683     } else {
684       AliError(Form("Unexpected class %s ! Valid classes are TVector3 or AliSurveyPoint",fLBTargets->At(iPoint)->ClassName()));
685       return 0;
686     }
687
688     lTransf.LocalToMaster(pl,pg);
689     pmg[0] = gBT->GetX();
690     pmg[1] = gBT->GetY();
691     pmg[2] = gBT->GetZ();
692     fBaseTrf->MasterToLocal(pmg,pml);
693 //     printf("l %d %f %f %f\n",iPoint,pl[0],pl[1],pl[2]);
694 //     printf("g %d %f %f %f\n",iPoint,pg[0],pg[1],pg[2]);
695 //     printf("ml %d %f %f %f\n",iPoint,pml[0],pml[1],pml[2]);
696 //     printf("mg %d %f %f %f\n",iPoint,gBT->GetX(),gBT->GetY(),gBT->GetZ());
697     lDiff[iPoint*(3+1)+0] = (pml[0]-pg[0]);
698     lDiff[iPoint*(3+1)+1] = (pml[1]-pg[1]);
699     lDiff[iPoint*(3+1)+2] = (pml[2]-pg[2]);
700     
701     lDiff[iPoint*(3+1)+3] = TMath::Sqrt(lDiff[iPoint*(3+1)+0]*lDiff[iPoint*(3+1)+0]+
702                                         lDiff[iPoint*(3+1)+1]*lDiff[iPoint*(3+1)+1]+
703                                         lDiff[iPoint*(3+1)+2]*lDiff[iPoint*(3+1)+2]);
704
705     lDiff[nPoints*(3+1)] += lDiff[iPoint*(3+1)+3]*lDiff[iPoint*(3+1)+3];
706   }
707                 
708   lDiff[nPoints*(3+1)] = TMath::Sqrt(lDiff[nPoints*(3+1)]);
709   return lDiff[nPoints*(3+1)];
710 }
711
712 Int_t AliMUONSurveyObj::CalculateBestTransf(Int_t iP1, Int_t iP2, Double_t *lXYZ, Double_t *lPTP) {
713
714   Double_t lPsi = lPTP[0];
715   Double_t lTht = lPTP[1];
716
717   Double_t pl1[3] = {0};
718   Double_t pl2[3] = {0};
719
720   if(!fLBTargets->At(iP1)||!fLBTargets->At(iP2)){
721     AliError(Form("Local target %d or %d is missing!",iP1,iP2));
722     return 0;
723   }
724
725   if(fLBTargets->At(iP1)->IsA()==TVector3::Class()){
726     TVector3 *lBT1 = (TVector3*)fLBTargets->At(iP1);
727     pl1[0]=lBT1->X();
728     pl1[1]=lBT1->Y();
729     pl1[2]=lBT1->Z();
730   } else if(fLBTargets->At(iP1)->IsA()==AliSurveyPoint::Class()) {
731     AliSurveyPoint *lBT1 = (AliSurveyPoint*)fLBTargets->At(iP1);
732     pl1[0]=lBT1->GetX();
733     pl1[1]=lBT1->GetY();
734     pl1[2]=lBT1->GetZ();
735   } else {
736     AliError(Form("Unexpected class %s ! Valid classes are TVector3 or AliSurveyPoint",fLBTargets->At(iP1)->ClassName()));
737     return 0;
738   }
739   if(fLBTargets->At(iP2)->IsA()==TVector3::Class()){
740     TVector3 *lBT2 = (TVector3*)fLBTargets->At(iP2);
741     pl2[0]=lBT2->X();
742     pl2[1]=lBT2->Y();
743     pl2[2]=lBT2->Z();
744   } else if(fLBTargets->At(iP2)->IsA()==AliSurveyPoint::Class()) {
745     AliSurveyPoint *lBT2 = (AliSurveyPoint*)fLBTargets->At(iP2);
746     pl2[0]=lBT2->GetX();
747     pl2[1]=lBT2->GetY();
748     pl2[2]=lBT2->GetZ();
749   } else {
750     AliError(Form("Unexpected class %s ! Valid classes are TVector3 or AliSurveyPoint",fLBTargets->At(iP2)->ClassName()));
751     return 0;
752   }
753
754   
755   AliMUONSurveyUtil *surveyUtil = AliMUONSurveyUtil::Instance();
756
757   // Xcenter functions
758   const char *fxcName = "fXcn00"; 
759   TF2 **fXc = new TF2*[2];
760   fxcName = "fXcn";
761   fXc[0] = new TF2(fxcName,surveyUtil,&AliMUONSurveyUtil::xnCenter,fXMin,fXMax,fYMin,fYMax,7,"AliMUONSurveyUtil","xnCenter");
762   fxcName = "fXcp";
763   fXc[1] = new TF2(fxcName,surveyUtil,&AliMUONSurveyUtil::xpCenter,fXMin,fXMax,fYMin,fYMax,7,"AliMUONSurveyUtil","xpCenter");
764
765   // Ycenter functions
766   const char *fycName = "fYcn00"; 
767   TF2 **fYc = new TF2*[2];
768   fycName = "fYcn";
769   fYc[0] = new TF2(fycName,surveyUtil,&AliMUONSurveyUtil::ynCenter,fYMin,fYMax,fYMin,fYMax,8,"AliMUONSurveyUtil","ynCenter");
770   fycName = "fYcp";
771   fYc[1] = new TF2(fycName,surveyUtil,&AliMUONSurveyUtil::ypCenter,fYMin,fYMax,fYMin,fYMax,8,"AliMUONSurveyUtil","ypCenter");   
772
773   // Zcenter functions
774   const char *fzcName = "fZcn00"; 
775   TF2 **fZc = new TF2*[2];
776   fzcName = "fZcn";
777   fZc[0] = new TF2(fzcName,surveyUtil,&AliMUONSurveyUtil::znCenter,fZMin,fZMax,fZMin,fZMax,8,"AliMUONSurveyUtil","znCenter");
778   fzcName = "fZcp";
779   fZc[1] = new TF2(fzcName,surveyUtil,&AliMUONSurveyUtil::zpCenter,fZMin,fZMax,fZMin,fZMax,8,"AliMUONSurveyUtil","zpCenter");   
780
781   // Phi rotation using xglobal coords functions
782   const char *fphixName = "fPhiXnn00"; 
783   TF2 ***fPhiX = new TF2**[2];
784   for (Int_t iX =0; iX<2; iX++) {
785     fPhiX[iX] = new TF2*[2];
786   }
787   fphixName = "fPhiXnn";
788   fPhiX[0][0] = new TF2(fphixName,surveyUtil,&AliMUONSurveyUtil::phixnn,fXMin,fXMax,fXMin,fXMax,7,"AliMUONSurveyUtil","phixnn");
789   fphixName = "fPhiXnp";
790   fPhiX[0][1] = new TF2(fphixName,surveyUtil,&AliMUONSurveyUtil::phixnp,fXMin,fXMax,fXMin,fXMax,7,"AliMUONSurveyUtil","phixnp");   
791   fphixName = "fPhiXpn";
792   fPhiX[1][0] = new TF2(fphixName,surveyUtil,&AliMUONSurveyUtil::phixpn,fXMin,fXMax,fXMin,fXMax,7,"AliMUONSurveyUtil","phixpn");
793   fphixName = "fPhiXpp";
794   fPhiX[1][1] = new TF2(fphixName,surveyUtil,&AliMUONSurveyUtil::phixpp,fXMin,fXMax,fXMin,fXMax,7,"AliMUONSurveyUtil","phixpp");   
795
796   // Phi rotation using yglobal coords functions
797   const char *fphiyName = "fPhiYnn00"; 
798   TF2 ***fPhiY = new TF2**[2];
799   for (Int_t iY =0; iY<2; iY++) {
800     fPhiY[iY] = new TF2*[2];
801   }
802   fphiyName = "fPhiYnn";
803   fPhiY[0][0] = new TF2(fphiyName,surveyUtil,&AliMUONSurveyUtil::phiynn,fYMin,fYMax,fYMin,fYMax,8,"AliMUONSurveyUtil","phiynn");
804   fphiyName = "fPhiYnp";
805   fPhiY[0][1] = new TF2(fphiyName,surveyUtil,&AliMUONSurveyUtil::phiynp,fYMin,fYMax,fYMin,fYMax,8,"AliMUONSurveyUtil","phiynp");   
806   fphiyName = "fPhiYpn";
807   fPhiY[1][0] = new TF2(fphiyName,surveyUtil,&AliMUONSurveyUtil::phiypn,fYMin,fYMax,fYMin,fYMax,8,"AliMUONSurveyUtil","phiypn");
808   fphiyName = "fPhiYpp";
809   fPhiY[1][1] = new TF2(fphiyName,surveyUtil,&AliMUONSurveyUtil::phiypp,fYMin,fYMax,fYMin,fYMax,8,"AliMUONSurveyUtil","phiypp");   
810   
811
812   // Set Parameters of functions
813   for(Int_t iS=0; iS<2; iS++){
814     fXc[iS]->SetParameters(pl1[0],pl1[1],pl1[2],pl2[0],pl2[1],pl2[2],lTht);
815     fYc[iS]->SetParameters(pl1[0],pl1[1],pl1[2],pl2[0],pl2[1],pl2[2],lPsi,lTht);
816     fZc[iS]->SetParameters(pl1[0],pl1[1],pl1[2],pl2[0],pl2[1],pl2[2],lPsi,lTht);
817 //     fXc[iS]->SetParameters(lBT1->X(),lBT1->Y(),lBT1->Z(),lBT2->X(),lBT2->Y(),lBT2->Z(),lTht);
818 //     fYc[iS]->SetParameters(lBT1->X(),lBT1->Y(),lBT1->Z(),lBT2->X(),lBT2->Y(),lBT2->Z(),lPsi,lTht);
819 //     fZc[iS]->SetParameters(lBT1->X(),lBT1->Y(),lBT1->Z(),lBT2->X(),lBT2->Y(),lBT2->Z(),lPsi,lTht);
820     for(Int_t jS=0; jS<2; jS++){
821       fPhiX[iS][jS]->SetParameters(pl1[0],pl1[1],pl1[2],pl2[0],pl2[1],pl2[2],lTht);
822       fPhiY[iS][jS]->SetParameters(pl1[0],pl1[1],pl1[2],pl2[0],pl2[1],pl2[2],lPsi,lTht);
823 //     fPhiX[iS][jS]->SetParameters(lBT1->X(),lBT1->Y(),lBT1->Z(),lBT2->X(),lBT2->Y(),lBT2->Z(),lTht);
824 //     fPhiY[iS][jS]->SetParameters(lBT1->X(),lBT1->Y(),lBT1->Z(),lBT2->X(),lBT2->Y(),lBT2->Z(),lPsi,lTht);
825     }
826   }
827
828   Double_t lCenTemp[3];
829   Double_t lRotTemp[3];
830
831   TGeoCombiTrans trfTemp;
832
833   Int_t nPoints = GetNGButtonTargets();
834
835   TArrayD lDiffTemp(nPoints*(3+1)+1);
836   TArrayD lDiffMin(nPoints*(3+1)+1);
837
838   for(Int_t i=0; i<nPoints*(3+1)+1; i++){
839     lDiffMin[i]=1000000.;
840     lDiffTemp[i]=0.;
841   }
842
843   //
844   // Calculate Detection Element Center from button targets
845   //    
846   
847   // Trying 2x*2y*2z*(2phi+2phi) possibilities
848   for(Int_t iX=0; iX<2; iX++){
849     for(Int_t iY=0; iY<2; iY++){
850       for(Int_t iZ=0; iZ<2; iZ++){
851         CalculateTranslation(fXc[iX],fYc[iY],fZc[iZ],iP1,iP2,lCenTemp);
852         
853         lRotTemp[0] = lPsi;
854         lRotTemp[1] = lTht;
855         for(Int_t iP=0; iP<2; iP++){
856           lRotTemp[2] = EvalFunction(fPhiX[iX][iP],iP1,iP2,"X");
857           
858           trfTemp.Clear();
859           trfTemp.RotateZ(TMath::RadToDeg()*lRotTemp[2]);
860           trfTemp.RotateY(TMath::RadToDeg()*lRotTemp[1]);
861           trfTemp.RotateX(TMath::RadToDeg()*lRotTemp[0]);
862           trfTemp.SetTranslation(lCenTemp);
863           
864           if(CalculateGlobalDiff(trfTemp,nPoints,lDiffTemp)<lDiffMin[nPoints*(3+1)]){
865             printf("Diffs");
866             for(Int_t i=0; i<nPoints*(3+1)+1; i++){
867               printf(" %f",lDiffTemp[i]); 
868             }
869             printf("\n");
870             printf(" : mycenX%dY%dZ%d(%f,%f,%f); rotx%d(%f,%f,%f)\n",iX,iY,iZ,lCenTemp[0],lCenTemp[1],lCenTemp[2],iP,lRotTemp[0],lRotTemp[1],lRotTemp[2]);
871             printf("Transformation improved ...\n");
872             for (int i=0; i<3; i++) {
873               lXYZ[i] = lCenTemp[i];
874             } 
875             lPTP[2] = lRotTemp[2];
876             for(Int_t i=0; i<nPoints*(3+1)+1; i++){
877               lDiffMin[i]=lDiffTemp[i];
878             }
879           }
880         }
881         for(Int_t iP=0; iP<2; iP++){
882           lRotTemp[2] = EvalFunction(fPhiY[iY][iP],iP1,iP2,"Y");
883           
884           trfTemp.Clear();
885           trfTemp.RotateZ(TMath::RadToDeg()*lRotTemp[2]);
886           trfTemp.RotateY(TMath::RadToDeg()*lRotTemp[1]);
887           trfTemp.RotateX(TMath::RadToDeg()*lRotTemp[0]);
888           trfTemp.SetTranslation(lCenTemp);
889           
890           if(CalculateGlobalDiff(trfTemp,nPoints,lDiffTemp)<lDiffMin[nPoints*(3+1)]){
891             printf("Diffs");
892             for(Int_t i=0; i<nPoints*(3+1)+1; i++){
893               printf(" %f",lDiffTemp[i]); 
894             }
895             printf("\n");
896             printf(" : mycenX%dY%dZ%d(%f,%f,%f); roty%d(%f,%f,%f)\n",iX,iY,iZ,lCenTemp[0],lCenTemp[1],lCenTemp[2],iP,lRotTemp[0],lRotTemp[1],lRotTemp[2]);
897             printf("Transformation improved ...\n");
898             for (int i=0; i<3; i++) {
899               lXYZ[i] = lCenTemp[i];
900             } 
901             lPTP[2] = lRotTemp[2];
902             for(Int_t i=0; i<nPoints*(3+1)+1; i++){
903               lDiffMin[i]=lDiffTemp[i];
904             }
905           }
906         }
907       }
908     }
909   }
910
911   for (Int_t i=0; i<2; i++) {
912     delete fXc[i];
913     delete fYc[i];
914     delete fZc[i];
915     for (Int_t j=0; j<2; j++) {
916       delete fPhiX[i][j];
917       delete fPhiY[i][j];
918     }
919     delete[] fPhiX[i];
920     delete[] fPhiY[i];
921   }
922   delete[] fXc;
923   delete[] fYc;
924   delete[] fZc;
925   delete[] fPhiX;
926   delete[] fPhiY;
927
928   if (lDiffMin[nPoints*(3+1)]>20) return 0;
929
930   return 1;
931 }
932
933 void AliMUONSurveyObj::CalculateMeanTransf(Double_t *lXYZ, Double_t *lPTP) {
934
935     Double_t xce=0.;
936     Double_t yce=0.;
937     Double_t zce=0.;
938     Double_t phi=0.;
939     
940     Int_t nPairs = 0;
941     Int_t nPoints = GetNGButtonTargets();
942     // Loop over all possible pairs of button tragets
943     for(Int_t iP1=0; iP1<nPoints; iP1++){
944       for(Int_t iP2=iP1+1; iP2<nPoints; iP2++){
945         printf("%d and %d\n",iP1,iP2);
946
947         if(CalculateBestTransf(iP1,iP2,lXYZ,lPTP)) {
948           nPairs++;
949         
950           xce+=lXYZ[0];
951           yce+=lXYZ[1];
952           zce+=lXYZ[2];
953           phi+=lPTP[2];
954         }
955       }
956     }
957
958     if (!nPairs) return;
959     
960     lXYZ[0]=xce/nPairs;
961     lXYZ[1]=yce/nPairs;
962     lXYZ[2]=zce/nPairs;
963     lPTP[2]=phi/nPairs;
964 }
965
966 void AliMUONSurveyObj::PrintLocalTrf() {
967   Double_t lRotTemp[3];
968   AliMUONSurveyUtil::MatrixToAngles(fLocalTrf->GetRotationMatrix(),lRotTemp);
969   printf("(%.3f %.3f %.3f), (%.6f %.6f %.6f)\n",fLocalTrf->GetTranslation()[0],fLocalTrf->GetTranslation()[1],fLocalTrf->GetTranslation()[2],lRotTemp[0],lRotTemp[1],lRotTemp[2]);
970 }
971
972 void AliMUONSurveyObj::PrintAlignTrf() {
973   Double_t lRotTemp[3];
974   AliMUONSurveyUtil::MatrixToAngles(fAlignTrf->GetRotationMatrix(),lRotTemp);
975   printf("(%.3f %.3f %.3f), (%.6f %.6f %.6f)\n",fAlignTrf->GetTranslation()[0],fAlignTrf->GetTranslation()[1],fAlignTrf->GetTranslation()[2],lRotTemp[0],lRotTemp[1],lRotTemp[2]);
976 }
977
978 void AliMUONSurveyObj::FillSTHistograms(TString baseNameC, TH2 *hSTc, TString baseNameA, TH2 *hSTa) {
979   if(baseNameC.IsNull()||!hSTc){
980     AliError("Need base name for points on side C and/or a histogram for them!");
981     return;
982   }
983   AliSurveyPoint *pointST = 0x0;
984   for (Int_t iPoint=0; iPoint<GetNStickerTargets(); iPoint++) {
985     pointST = GetStickerTarget(iPoint);
986     if (!pointST) continue;
987     if (pointST->GetPointName().Contains(baseNameC)){
988       hSTc->Fill(pointST->GetX(),pointST->GetY(),-pointST->GetZ());
989     } else if ((!baseNameA.IsNull()) && 
990               (pointST->GetPointName().Contains(baseNameA))) {
991       if (!hSTa){
992         AliError("Base name for points on side A provided but no histogram for them!");
993         continue;
994       }
995       hSTa->Fill(pointST->GetX(),pointST->GetY(),-pointST->GetZ());
996     }
997   }
998 }
999
1000 Double_t AliMUONSurveyObj::GetAlignResX() {
1001   if(!fFitter) {
1002     AliError("There is no fitter for this object! X resolution will be 0.");
1003     return 0.;
1004   }
1005   return fFitter->GetParError(0);
1006 }
1007
1008 Double_t AliMUONSurveyObj::GetAlignResY() {
1009   if(!fFitter) {
1010     AliError("There is no fitter for this object! Y resolution will be 0.");
1011     return 0.;
1012   }
1013   return fFitter->GetParError(1);
1014 }