Fix from for producing a dataset via the alien plugin. Redirecting the alien 'find...
[u/mrichter/AliRoot.git] / MUON / AliMUONSurveyObj.cxx
CommitLineData
ba8b0266 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
46void SurveyFcn(int &npar, double *g, double &f, double *par, int iflag);
47
48/// \cond CLASSIMP
49ClassImp(AliMUONSurveyObj)
50/// \endcond
51
52AliMUONSurveyObj::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
86AliMUONSurveyObj::~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
122void AliMUONSurveyObj::AddStickerTarget(AliSurveyPoint *stPoint){
123 fSTargets->Add(stPoint);
124}
125
126void AliMUONSurveyObj::AddGButtonTarget(AliSurveyPoint *btPoint){
127 fGBTargets->Add(btPoint);
128}
129
130void AliMUONSurveyObj::AddLButtonTarget(AliSurveyPoint *btPoint){
131 fLBTargets->Add(btPoint);
132}
133
134void AliMUONSurveyObj::AddLButtonTarget(TVector3 *btVector){
135 fLBTargets->Add(btVector);
136}
137
138Int_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
174Int_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
211Int_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
248Int_t AliMUONSurveyObj::GetNStickerTargets() {
249 return fSTargets->GetEntriesFast();
250}
251
252AliSurveyPoint* 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
262Int_t AliMUONSurveyObj::GetNGButtonTargets() {
263 return fGBTargets->GetEntriesFast();
264}
265
266AliSurveyPoint* 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
276Int_t AliMUONSurveyObj::GetNLButtonTargets() {
277 return fGBTargets->GetEntriesFast();
278}
279
280AliSurveyPoint* 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
300void 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
308void 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
319void 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
334Double_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
367Double_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//_____________________________________________________________________________
427void 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);
94bf739c 438 if (iflag==3) {}
439 if (npar) {}
440 if (g) {} // no warnings about unused stuff...
ba8b0266 441
442}
443
444//_____________________________________________________________________________
445Int_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//_____________________________________________________________________________
504Int_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
582Double_t AliMUONSurveyObj::EvalFunction(TF2 *lFunction, Int_t iP1, Int_t iP2, 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
643void 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
651Double_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
712Int_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 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 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 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 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 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
933void 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
966void 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
972void 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
978void 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
1000Double_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
1008Double_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}