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 **************************************************************************/
16 /* $Id: AliMUONAlignment.cxx 51000 2011-08-08 17:58:17Z ivana $ */
18 //-----------------------------------------------------------------------------
19 /// \class AliMUONAlignment
20 /// Alignment class for the ALICE DiMuon spectrometer
22 /// MUON specific alignment class which interface to AliMillepede.
23 /// For each track ProcessTrack calculates the local and global derivatives
24 /// at each cluster and fill the corresponding local equations. Provide methods
25 /// for fixing or constraining detection elements for best results.
27 /// \author Bruce Becker, Javier Castillo
28 //-----------------------------------------------------------------------------
30 #include "AliMUONAlignment.h"
31 #include "AliMUONTrack.h"
32 #include "AliMUONTrackParam.h"
33 #include "AliMUONVCluster.h"
34 #include "AliMUONGeometryTransformer.h"
35 #include "AliMUONGeometryModuleTransformer.h"
36 #include "AliMUONGeometryDetElement.h"
37 #include "AliMUONGeometryBuilder.h"
38 #include "AliMillePede2.h"
40 #include "AliMpExMap.h"
41 #include "AliMpExMapIterator.h"
43 #include "AliAlignObjMatrix.h"
47 #include <TMatrixDSym.h>
48 #include <TClonesArray.h>
49 #include <TGraphErrors.h>
52 ClassImp(AliMUONAlignment)
55 //_____________________________________________________________________
57 const Int_t AliMUONAlignment::fgNDetElemCh[AliMUONAlignment::fgNCh] = { 4, 4, 4, 4, 18, 18, 26, 26, 26, 26 };
58 const Int_t AliMUONAlignment::fgSNDetElemCh[AliMUONAlignment::fgNCh+1] = { 0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156 };
60 //_____________________________________________________________________
61 /// self initialized array, used for adding constraints
70 for( Int_t i=0; i < AliMUONAlignment::fNGlobal; ++i )
75 Double_t values[AliMUONAlignment::fNGlobal];
83 Array& operator = (const Array& );
87 //_____________________________________________________________________
88 AliMUONAlignment::AliMUONAlignment()
90 fInitialized( kFALSE ),
94 fResCutInitial( 100 ),
103 fGeoCombiTransInverse()
109 // default allowed variations
110 fAllowVar[0] = 0.5; // x
111 fAllowVar[1] = 0.5; // y
112 fAllowVar[2] = 0.01; // phi_z
113 fAllowVar[3] = 5; // z
115 // initialize millepede
116 fMillepede = new AliMillePede2();
118 // initialize degrees of freedom
119 // by default all parameters are free
120 for( Int_t iPar = 0; iPar < fNGlobal; ++iPar )
121 { fGlobalParameterStatus[iPar] = kFreeParId; }
123 // initialize local equations
124 for(int i=0; i<fNLocal; ++i )
125 { fLocalDerivatives[i] = 0.0; }
127 for(int i=0; i<fNGlobal; ++i )
128 { fGlobalDerivatives[i] = 0.0; }
132 //_____________________________________________________________________
133 AliMUONAlignment::~AliMUONAlignment()
138 //_____________________________________________________________________
139 void AliMUONAlignment::Init( void )
145 must be called after necessary detectors have been fixed,
146 but before constrains are added and before global parameters initial value are set
149 { AliFatal( "Millepede already initialized" ); }
151 // assign proper groupID to free parameters
153 for( Int_t iPar = 0; iPar < fNGlobal; ++iPar )
156 if( fGlobalParameterStatus[iPar] == kFixedParId )
158 // fixed parameters are left unchanged
161 } else if( fGlobalParameterStatus[iPar] == kFreeParId || fGlobalParameterStatus[iPar] == kGroupBaseId ) {
163 // free parameters or first element of group are assigned a new group id
164 fGlobalParameterStatus[iPar] = nGlobal++;
167 } else if( fGlobalParameterStatus[iPar] < kGroupBaseId ) {
169 // get detector element id from status, get chamber parameter id
170 const Int_t iDeBase( kGroupBaseId - 1 - fGlobalParameterStatus[iPar] );
171 const Int_t iParBase = iPar%fgNParCh;
174 if( iDeBase < 0 || iDeBase >= iPar/fgNParCh )
175 { AliFatal( Form( "Group for parameter index %i has wrong base detector element: %i", iPar, iDeBase ) ); }
177 // assign identical group id to current
178 fGlobalParameterStatus[iPar] = fGlobalParameterStatus[iDeBase*fgNParCh + iParBase];
179 AliInfo( Form( "Parameter %i grouped to detector %i (%s)", iPar, iDeBase, GetParameterMaskString( 1<<iParBase ).Data() ) );
181 } else AliFatal( Form( "Unrecognized parameter status for index %i: %i", iPar, fGlobalParameterStatus[iPar] ) );
185 AliInfo( Form( "Free Parameters: %i out of %i", nGlobal, fNGlobal ) );
187 // initialize millepede
188 fMillepede->InitMille( fNGlobal, fNLocal, fNStdDev, fResCut, fResCutInitial, fGlobalParameterStatus );
189 fInitialized = kTRUE;
192 for( Int_t iPar = 0; iPar < fgNParCh; ++iPar )
193 { AliInfo( Form( "fAllowVar[%i]= %f", iPar, fAllowVar[iPar] ) ); }
195 // set allowed variations for all parameters
196 for( Int_t iDet = 0; iDet < fgNDetElem; ++iDet )
198 for( Int_t iPar = 0; iPar < fgNParCh; ++iPar )
199 { fMillepede->SetParSigma( iDet*fgNParCh + iPar, fAllowVar[iPar] ); }
203 if (fStartFac>1) fMillepede->SetIterations(fStartFac);
207 //_____________________________________________________
208 AliMillePedeRecord* AliMUONAlignment::ProcessTrack( AliMUONTrack* track, Bool_t doAlignment, Double_t weight )
210 /// process track for alignment minimization
212 returns the alignment records for this track.
213 They can be stored in some output for later reprocessing.
216 // reset track records
217 fTrackRecord.Reset();
218 if( fMillepede->GetRecord() ) fMillepede->GetRecord()->Reset();
220 // get number of track parameters
221 Int_t nTrackParam = track->GetTrackParamAtCluster()->GetEntries();
223 Bool_t first( kTRUE );
224 for( Int_t iTrackParam = 0; iTrackParam < nTrackParam; ++iTrackParam )
228 AliMUONTrackParam* trackParam( (AliMUONTrackParam *) track->GetTrackParamAtCluster()->At(iTrackParam) );
229 if( !trackParam ) continue;
231 AliMUONVCluster* cluster = trackParam->GetClusterPtr();
232 if( !cluster ) continue;
234 // fill local variables for this position --> one measurement
235 FillDetElemData( cluster );
236 FillRecPointData( cluster );
238 // unbias and store track parameters
239 if( fUnbias && !UnbiasTrackParamData( trackParam ) ) continue;
240 FillTrackParamData( trackParam );
245 // for first valid cluster, save track position as "starting" values
248 fTrackPos0[0] = fTrackPos[0];
249 fTrackPos0[1] = fTrackPos[1];
250 fTrackPos0[2] = fTrackPos[2];
251 fTrackSlope0[0] = fTrackSlope[0];
252 fTrackSlope0[1] = fTrackSlope[1];
256 // 'inverse' (GlobalToLocal) rotation matrix
257 const Double_t* r( fGeoCombiTransInverse.GetRotationMatrix() );
259 // calculate measurements
263 // use residuals (cluster - track) for measurement
264 fMeas[0] = r[0]*(fClustPos[0] - fTrackPos[0]) + r[1]*(fClustPos[1] - fTrackPos[1]);
265 fMeas[1] = r[3]*(fClustPos[0] - fTrackPos[0]) + r[4]*(fClustPos[1] - fTrackPos[1]);
269 // use cluster position for measurement
270 fMeas[0] = ( r[0]*fClustPos[0] + r[1]*fClustPos[1] );
271 fMeas[1] = ( r[3]*fClustPos[0] + r[4]*fClustPos[1] );
275 // Set local equations
282 fMillepede->SetRecordRun(fRunNumber);
283 fMillepede->SetRecordWeight(weight);
284 fTrackRecord = *fMillepede->GetRecord();
289 fMillepede->SaveRecordData();
293 return &fTrackRecord;
297 //______________________________________________________________________________
298 void AliMUONAlignment::ProcessTrack( AliMillePedeRecord* trackRecord )
300 /// process track record
301 if( !trackRecord ) return;
303 // make sure record storage is initialized
304 if( !fMillepede->GetRecord() ) fMillepede->InitDataRecStorage();
307 *fMillepede->GetRecord() = *trackRecord;
310 fMillepede->SaveRecordData();
316 //_____________________________________________________________________
317 void AliMUONAlignment::FixAll( UInt_t mask )
319 /// fix parameters matching mask, for all chambers
320 AliInfo( Form( "Fixing %s for all detector elements", GetParameterMaskString( mask ).Data() ) );
323 for( Int_t i = 0; i < fgNDetElem; ++i )
325 if( mask & ParX ) FixParameter(i, 0);
326 if( mask & ParY ) FixParameter(i, 1);
327 if( mask & ParTZ ) FixParameter(i, 2);
328 if( mask & ParZ ) FixParameter(i, 3);
333 //_____________________________________________________________________
334 void AliMUONAlignment::FixChamber( Int_t iCh, UInt_t mask )
336 /// fix parameters matching mask, for all detector elements in a given chamber, counting from 1
339 if( iCh < 1 || iCh > 10 )
340 { AliFatal( Form( "Invalid chamber index %i", iCh ) ); }
342 // get first and last element
343 const Int_t iDetElemFirst = fgSNDetElemCh[iCh-1];
344 const Int_t iDetElemLast = fgSNDetElemCh[iCh];
345 for( Int_t i = iDetElemFirst; i < iDetElemLast; ++i )
348 AliInfo( Form( "Fixing %s for detector element %i", GetParameterMaskString(mask).Data(), i ) );
350 if( mask & ParX ) FixParameter(i, 0);
351 if( mask & ParY ) FixParameter(i, 1);
352 if( mask & ParTZ ) FixParameter(i, 2);
353 if( mask & ParZ ) FixParameter(i, 3);
358 //_____________________________________________________________________
359 void AliMUONAlignment::FixDetElem( Int_t iDetElemId, UInt_t mask )
361 /// fix parameters matching mask, for a given detector element, counting from 0
362 const Int_t iDet( GetDetElemNumber( iDetElemId ) );
363 if ( mask & ParX ) FixParameter(iDet, 0);
364 if ( mask & ParY ) FixParameter(iDet, 1);
365 if ( mask & ParTZ ) FixParameter(iDet, 2);
366 if ( mask & ParZ ) FixParameter(iDet, 3);
370 //_____________________________________________________________________
371 void AliMUONAlignment::FixHalfSpectrometer( const Bool_t *lChOnOff, UInt_t sidesMask, UInt_t mask )
374 /// Fix parameters matching mask for all detectors in selected chambers and selected sides of the spectrometer
375 for( Int_t i = 0; i < fgNDetElem; ++i )
378 // get chamber matching detector
379 const Int_t iCh( GetChamberId(i) );
380 if( !lChOnOff[iCh-1] ) continue;
382 // get detector element in chamber
383 Int_t lDetElemNumber = i-fgSNDetElemCh[iCh-1];
385 // skip detector if its side is off
387 if( iCh>=1 && iCh<=4 )
389 if( lDetElemNumber == 0 && !( sidesMask & SideTopRight ) ) continue;
390 if( lDetElemNumber == 1 && !( sidesMask & SideTopLeft ) ) continue;
391 if( lDetElemNumber == 2 && !( sidesMask & SideBottomLeft ) ) continue;
392 if( lDetElemNumber == 3 && !( sidesMask & SideBottomRight ) ) continue;
396 if (iCh>=5 && iCh<=6)
398 if( lDetElemNumber >= 0 && lDetElemNumber <= 4 && !( sidesMask & SideTopRight ) ) continue;
399 if( lDetElemNumber >= 5 && lDetElemNumber <= 10 && !( sidesMask & SideTopLeft ) ) continue;
400 if( lDetElemNumber >= 11 && lDetElemNumber <= 13 && !( sidesMask & SideBottomLeft ) ) continue;
401 if( lDetElemNumber >= 14 && lDetElemNumber <= 17 && !( sidesMask & SideBottomRight ) ) continue;
405 if (iCh>=7 && iCh<=10)
407 if( lDetElemNumber >= 0 && lDetElemNumber <= 6 && !( sidesMask & SideTopRight ) ) continue;
408 if( lDetElemNumber >= 7 && lDetElemNumber <= 13 && !( sidesMask & SideTopLeft ) ) continue;
409 if( lDetElemNumber >= 14 && lDetElemNumber <= 19 && !( sidesMask & SideBottomLeft ) ) continue;
410 if( lDetElemNumber >= 20 && lDetElemNumber <= 25 && !( sidesMask & SideBottomRight ) ) continue;
413 // detector is accepted, fix it
414 FixDetElem( i, mask );
420 //______________________________________________________________________
421 void AliMUONAlignment::FixParameter( Int_t iPar )
424 /// fix a given parameter, counting from 0
426 { AliFatal( "Millepede already initialized" ); }
428 fGlobalParameterStatus[iPar] = kFixedParId;
433 //_____________________________________________________________________
434 void AliMUONAlignment::ReleaseChamber( Int_t iCh, UInt_t mask )
436 /// release parameters matching mask, for all detector elements in a given chamber, counting from 1
439 if( iCh < 1 || iCh > 10 )
440 { AliFatal( Form( "Invalid chamber index %i", iCh ) ); }
442 // get first and last element
443 const Int_t iDetElemFirst = fgSNDetElemCh[iCh-1];
444 const Int_t iDetElemLast = fgSNDetElemCh[iCh];
445 for( Int_t i = iDetElemFirst; i < iDetElemLast; ++i )
448 AliInfo( Form( "Releasing %s for detector element %i", GetParameterMaskString(mask).Data(), i ) );
450 if( mask & ParX ) ReleaseParameter(i, 0);
451 if( mask & ParY ) ReleaseParameter(i, 1);
452 if( mask & ParTZ ) ReleaseParameter(i, 2);
453 if( mask & ParZ ) ReleaseParameter(i, 3);
458 //_____________________________________________________________________
459 void AliMUONAlignment::ReleaseDetElem( Int_t iDetElemId, UInt_t mask )
461 /// release parameters matching mask, for a given detector element, counting from 0
462 const Int_t iDet( GetDetElemNumber( iDetElemId ) );
463 if ( mask & ParX ) ReleaseParameter(iDet, 0);
464 if ( mask & ParY ) ReleaseParameter(iDet, 1);
465 if ( mask & ParTZ ) ReleaseParameter(iDet, 2);
466 if ( mask & ParZ ) ReleaseParameter(iDet, 3);
470 //______________________________________________________________________
471 void AliMUONAlignment::ReleaseParameter( Int_t iPar )
474 /// release a given parameter, counting from 0
476 { AliFatal( "Millepede already initialized" ); }
478 fGlobalParameterStatus[iPar] = kFreeParId;
482 //_____________________________________________________________________
483 void AliMUONAlignment::GroupChamber( Int_t iCh, UInt_t mask )
485 /// group parameters matching mask for all detector elements in a given chamber, counting from 1
486 if( iCh < 1 || iCh > 10 )
487 { AliFatal( Form( "Invalid chamber index %i", iCh ) ); }
489 const Int_t detElemMin = 100*iCh;
490 const Int_t detElemMax = 100*iCh + fgNDetElemCh[iCh]-1;
491 GroupDetElems( detElemMin, detElemMax, mask );
495 //_____________________________________________________________________
496 void AliMUONAlignment::GroupDetElems( Int_t detElemMin, Int_t detElemMax, UInt_t mask )
498 /// group parameters matching mask for all detector elements between min and max
499 // check number of detector elements
500 const Int_t nDetElem = detElemMax - detElemMin + 1;
502 { AliFatal( Form( "Requested group of DEs %d-%d contains less than 2 DE's", detElemMin, detElemMax ) ); }
505 Int_t* detElemList = new int[nDetElem];
506 for( Int_t i = 0; i < nDetElem; ++i )
507 { detElemList[i] = detElemMin+i; }
510 GroupDetElems( detElemList, nDetElem, mask );
511 delete[] detElemList;
515 //_____________________________________________________________________
516 void AliMUONAlignment::GroupDetElems( Int_t* detElemList, Int_t nDetElem, UInt_t mask )
518 /// group parameters matching mask for all detector elements in list
520 { AliFatal( "Millepede already initialized" ); }
522 const Int_t iDeBase( GetDetElemNumber( detElemList[0] ) );
523 for( Int_t i = 0; i < nDetElem; ++i )
525 const Int_t iDeCurrent( GetDetElemNumber( detElemList[i] ) );
526 if( mask & ParX ) fGlobalParameterStatus[iDeCurrent*fgNParCh + 0] = (i==0) ? kGroupBaseId : (kGroupBaseId-iDeBase-1);
527 if( mask & ParY ) fGlobalParameterStatus[iDeCurrent*fgNParCh + 1] = (i==0) ? kGroupBaseId : (kGroupBaseId-iDeBase-1);
528 if( mask & ParTZ ) fGlobalParameterStatus[iDeCurrent*fgNParCh + 2] = (i==0) ? kGroupBaseId : (kGroupBaseId-iDeBase-1);
529 if( mask & ParZ ) fGlobalParameterStatus[iDeCurrent*fgNParCh + 3] = (i==0) ? kGroupBaseId : (kGroupBaseId-iDeBase-1);
531 if( i== 0 ) AliInfo( Form( "Creating new group for detector %i and variable %s", detElemList[i], GetParameterMaskString( mask ).Data() ) );
532 else AliInfo( Form( "Adding detector element %i to current group", detElemList[i] ) );
537 //______________________________________________________________________
538 void AliMUONAlignment::SetChamberNonLinear( Int_t iCh, UInt_t mask )
540 /// Set parameters matching mask as non linear, for all detector elements in a given chamber, counting from 1
541 const Int_t iDetElemFirst = fgSNDetElemCh[iCh-1];
542 const Int_t iDetElemLast = fgSNDetElemCh[iCh];
543 for( Int_t i = iDetElemFirst; i < iDetElemLast; ++i )
546 if( mask & ParX ) SetParameterNonLinear(i, 0);
547 if( mask & ParY ) SetParameterNonLinear(i, 1);
548 if( mask & ParTZ ) SetParameterNonLinear(i, 2);
549 if( mask & ParZ ) SetParameterNonLinear(i, 3);
555 //_____________________________________________________________________
556 void AliMUONAlignment::SetDetElemNonLinear( Int_t iDetElemId, UInt_t mask )
558 /// Set parameters matching mask as non linear, for a given detector element, counting from 0
559 const Int_t iDet( GetDetElemNumber( iDetElemId ) );
560 if ( mask & ParX ) SetParameterNonLinear(iDet, 0);
561 if ( mask & ParY ) SetParameterNonLinear(iDet, 1);
562 if ( mask & ParTZ ) SetParameterNonLinear(iDet, 2);
563 if ( mask & ParZ ) SetParameterNonLinear(iDet, 3);
567 //______________________________________________________________________
568 void AliMUONAlignment::SetParameterNonLinear( Int_t iPar )
570 /// Set nonlinear flag for parameter iPar
572 { AliFatal( "Millepede not initialized" ); }
574 fMillepede->SetNonLinear( iPar );
575 AliInfo( Form( "Parameter %i set to non linear", iPar ) );
578 //______________________________________________________________________
579 void AliMUONAlignment::AddConstraints( const Bool_t *lChOnOff, UInt_t mask )
581 /// Add constraint equations for selected chambers and degrees of freedom
588 for( Int_t i = 0; i < fgNDetElem; ++i )
591 // get chamber matching detector
592 const Int_t iCh( GetChamberId(i) );
596 if( mask & ParX ) fConstraintX.values[i*fgNParCh+0]=1.0;
597 if( mask & ParY ) fConstraintY.values[i*fgNParCh+1]=1.0;
598 if( mask & ParTZ ) fConstraintTZ.values[i*fgNParCh+2]=1.0;
599 if( mask & ParZ ) fConstraintTZ.values[i*fgNParCh+3]=1.0;
604 if( mask & ParX ) AddConstraint(fConstraintX.values,0.0);
605 if( mask & ParY ) AddConstraint(fConstraintY.values,0.0);
606 if( mask & ParTZ ) AddConstraint(fConstraintTZ.values,0.0);
607 if( mask & ParZ ) AddConstraint(fConstraintZ.values,0.0);
611 //______________________________________________________________________
612 void AliMUONAlignment::AddConstraints(const Bool_t *lChOnOff, const Bool_t *lVarXYT, UInt_t sidesMask )
616 - is there not redundancy/inconsistency between lDetTLBR and lSpecLROnOff ? shouldn't we use only lDetTLBR ?
617 - why is weight ignored for ConstrainT and ConstrainB
618 - why is there no constrain on z
621 /// Add constraint equations for selected chambers, degrees of freedom and detector half
622 Double_t lMeanY = 0.;
623 Double_t lSigmaY = 0.;
624 Double_t lMeanZ = 0.;
625 Double_t lSigmaZ = 0.;
628 for( Int_t i = 0; i < fgNDetElem; ++i )
631 // get chamber matching detector
632 const Int_t iCh( GetChamberId(i) );
634 // skip detector if chamber is off
635 if( lChOnOff[iCh-1] ) continue;
637 // get detector element id from detector element number
638 const Int_t lDetElemNumber = i-fgSNDetElemCh[iCh-1];
639 const Int_t lDetElemId = iCh*100+lDetElemNumber;
641 // skip detector if its side is off
643 if( iCh>=1 && iCh<=4 )
645 if( lDetElemNumber == 0 && !( sidesMask & SideTopRight ) ) continue;
646 if( lDetElemNumber == 1 && !( sidesMask & SideTopLeft ) ) continue;
647 if( lDetElemNumber == 2 && !( sidesMask & SideBottomLeft ) ) continue;
648 if( lDetElemNumber == 3 && !( sidesMask & SideBottomRight ) ) continue;
652 if (iCh>=5 && iCh<=6)
654 if( lDetElemNumber >= 0 && lDetElemNumber <= 4 && !( sidesMask & SideTopRight ) ) continue;
655 if( lDetElemNumber >= 5 && lDetElemNumber <= 10 && !( sidesMask & SideTopLeft ) ) continue;
656 if( lDetElemNumber >= 11 && lDetElemNumber <= 13 && !( sidesMask & SideBottomLeft ) ) continue;
657 if( lDetElemNumber >= 14 && lDetElemNumber <= 17 && !( sidesMask & SideBottomRight ) ) continue;
661 if (iCh>=7 && iCh<=10)
663 if( lDetElemNumber >= 0 && lDetElemNumber <= 6 && !( sidesMask & SideTopRight ) ) continue;
664 if( lDetElemNumber >= 7 && lDetElemNumber <= 13 && !( sidesMask & SideTopLeft ) ) continue;
665 if( lDetElemNumber >= 14 && lDetElemNumber <= 19 && !( sidesMask & SideBottomLeft ) ) continue;
666 if( lDetElemNumber >= 20 && lDetElemNumber <= 25 && !( sidesMask & SideBottomRight ) ) continue;
669 // get global x, y and z position
670 Double_t lDetElemGloX = 0.;
671 Double_t lDetElemGloY = 0.;
672 Double_t lDetElemGloZ = 0.;
673 fTransform->Local2Global( lDetElemId, 0, 0, 0, lDetElemGloX, lDetElemGloY, lDetElemGloZ );
675 // increment mean Y, mean Z, sigmas and number of accepted detectors
676 lMeanY += lDetElemGloY;
677 lSigmaY += lDetElemGloY*lDetElemGloY;
678 lMeanZ += lDetElemGloZ;
679 lSigmaZ += lDetElemGloZ*lDetElemGloZ;
684 // calculate mean values
686 lSigmaY /= lNDetElem;
687 lSigmaY = TMath::Sqrt(lSigmaY-lMeanY*lMeanY);
689 lSigmaZ /= lNDetElem;
690 lSigmaZ = TMath::Sqrt(lSigmaZ-lMeanZ*lMeanZ);
691 AliInfo( Form( "Used %i DetElem, MeanZ= %f , SigmaZ= %f", lNDetElem,lMeanZ,lSigmaZ ) );
693 // create all possible arrays
694 Array fConstraintX[4]; //Array for constraint equation X
695 Array fConstraintY[4]; //Array for constraint equation Y
696 Array fConstraintP[4]; //Array for constraint equation P
697 Array fConstraintXZ[4]; //Array for constraint equation X vs Z
698 Array fConstraintYZ[4]; //Array for constraint equation Y vs Z
699 Array fConstraintPZ[4]; //Array for constraint equation P vs Z
701 // do we really need these ?
702 Array fConstraintXY[4]; //Array for constraint equation X vs Y
703 Array fConstraintYY[4]; //Array for constraint equation Y vs Y
704 Array fConstraintPY[4]; //Array for constraint equation P vs Y
706 // fill Bool_t sides array based on masks, for convenience
708 lDetTLBR[0] = sidesMask & SideTop;
709 lDetTLBR[1] = sidesMask & SideLeft;
710 lDetTLBR[2] = sidesMask & SideBottom;
711 lDetTLBR[3] = sidesMask & SideRight;
713 for( Int_t i = 0; i < fgNDetElem; ++i )
716 // get chamber matching detector
717 const Int_t iCh( GetChamberId(i) );
719 // skip detector if chamber is off
720 if( !lChOnOff[iCh-1] ) continue;
722 // get detector element id from detector element number
723 const Int_t lDetElemNumber = i-fgSNDetElemCh[iCh-1];
724 const Int_t lDetElemId = iCh*100+lDetElemNumber;
726 // get global x, y and z position
727 Double_t lDetElemGloX = 0.;
728 Double_t lDetElemGloY = 0.;
729 Double_t lDetElemGloZ = 0.;
730 fTransform->Local2Global( lDetElemId, 0, 0, 0, lDetElemGloX, lDetElemGloY, lDetElemGloZ );
733 for( Int_t iSide = 0; iSide < 4; iSide++ )
736 // skip if side is not selected
737 if( !lDetTLBR[iSide] ) continue;
739 // skip detector if it is not in the selected side
741 if( iCh>=1 && iCh<=4 )
743 if( lDetElemNumber == 0 && !(iSide == 0 || iSide == 3) ) continue; // top-right
744 if( lDetElemNumber == 1 && !(iSide == 0 || iSide == 1) ) continue; // top-left
745 if( lDetElemNumber == 2 && !(iSide == 2 || iSide == 1) ) continue; // bottom-left
746 if( lDetElemNumber == 3 && !(iSide == 2 || iSide == 3) ) continue; // bottom-right
750 if (iCh>=5 && iCh<=6)
752 if( lDetElemNumber >= 0 && lDetElemNumber <= 4 && !(iSide == 0 || iSide == 3) ) continue; // top-right
753 if( lDetElemNumber >= 5 && lDetElemNumber <= 9 && !(iSide == 0 || iSide == 1) ) continue; // top-left
754 if( lDetElemNumber >= 10 && lDetElemNumber <= 13 && !(iSide == 2 || iSide == 1) ) continue; // bottom-left
755 if( lDetElemNumber >= 14 && lDetElemNumber <= 17 && !(iSide == 2 || iSide == 3) ) continue; // bottom-right
759 if (iCh>=7 && iCh<=10)
761 if( lDetElemNumber >= 0 && lDetElemNumber <= 6 && !(iSide == 0 || iSide == 3) ) continue; // top-right
762 if( lDetElemNumber >= 7 && lDetElemNumber <= 13 && !(iSide == 0 || iSide == 1) ) continue; // top-left
763 if( lDetElemNumber >= 14 && lDetElemNumber <= 19 && !(iSide == 2 || iSide == 1) ) continue; // bottom-left
764 if( lDetElemNumber >= 20 && lDetElemNumber <= 25 && !(iSide == 2 || iSide == 3) ) continue; // bottom-right
768 if( lVarXYT[0] ) fConstraintX[iSide].values[i*fgNParCh+0] = 1;
771 if( lVarXYT[1] ) fConstraintY[iSide].values[i*fgNParCh+1] = 1;
773 // constrain phi (rotation around z)
774 if( lVarXYT[2] ) fConstraintP[iSide].values[i*fgNParCh+2] = 1;
777 if( lVarXYT[3] ) fConstraintXZ[iSide].values[i*fgNParCh+0] = (lDetElemGloZ-lMeanZ)/lSigmaZ;
780 if( lVarXYT[4] ) fConstraintYZ[iSide].values[i*fgNParCh+1] = (lDetElemGloZ-lMeanZ)/lSigmaZ;
783 if( lVarXYT[5] ) fConstraintPZ[iSide].values[i*fgNParCh+2] = (lDetElemGloZ-lMeanZ)/lSigmaZ;
786 if( lVarXYT[6] ) fConstraintXY[iSide].values[i*fgNParCh+0] = (lDetElemGloY-lMeanY)/lSigmaY;
789 if( lVarXYT[7] ) fConstraintYY[iSide].values[i*fgNParCh+1] = (lDetElemGloY-lMeanY)/lSigmaY;
792 if( lVarXYT[8] ) fConstraintPY[iSide].values[i*fgNParCh+2] = (lDetElemGloY-lMeanY)/lSigmaY;
798 // pass constraints to millepede
799 for( Int_t iSide = 0; iSide < 4; iSide++ )
801 // skip if side is not selected
802 if( !lDetTLBR[iSide] ) continue;
804 if( lVarXYT[0] ) AddConstraint(fConstraintX[iSide].values,0.0);
805 if( lVarXYT[1] ) AddConstraint(fConstraintY[iSide].values,0.0);
806 if( lVarXYT[2] ) AddConstraint(fConstraintP[iSide].values,0.0);
807 if( lVarXYT[3] ) AddConstraint(fConstraintXZ[iSide].values,0.0);
808 if( lVarXYT[4] ) AddConstraint(fConstraintYZ[iSide].values,0.0);
809 if( lVarXYT[5] ) AddConstraint(fConstraintPZ[iSide].values,0.0);
810 if( lVarXYT[6] ) AddConstraint(fConstraintXY[iSide].values,0.0);
811 if( lVarXYT[7] ) AddConstraint(fConstraintYY[iSide].values,0.0);
812 if( lVarXYT[8] ) AddConstraint(fConstraintPY[iSide].values,0.0);
817 //______________________________________________________________________
818 void AliMUONAlignment::InitGlobalParameters(Double_t *par)
820 /// Initialize global parameters with par array
822 { AliFatal( "Millepede is not initialized" ); }
824 fMillepede->SetGlobalParameters(par);
827 //______________________________________________________________________
828 void AliMUONAlignment::SetAllowedVariation( Int_t iPar, Double_t value )
830 /// "Encouraged" variation for degrees of freedom
831 // check initialization
833 { AliFatal( "Millepede already initialized" ); }
835 // check initialization
836 if( !(iPar >= 0 && iPar < fgNParCh ) )
837 { AliFatal( Form( "Invalid index: %i", iPar ) ); }
839 fAllowVar[iPar] = value;
842 //______________________________________________________________________
843 void AliMUONAlignment::SetSigmaXY(Double_t sigmaX, Double_t sigmaY)
846 /// Set expected measurement resolution
851 for( Int_t i=0; i<2; ++i )
852 { AliInfo( Form( "fSigma[%i]=%f", i, fSigma[i] ) ); }
856 //_____________________________________________________
857 void AliMUONAlignment::GlobalFit( Double_t *parameters, Double_t *errors, Double_t *pulls )
860 /// Call global fit; Global parameters are stored in parameters
861 fMillepede->GlobalFit( parameters, errors, pulls );
863 AliInfo( "Done fitting global parameters" );
864 for( int iDet=0; iDet<fgNDetElem; ++iDet )
866 AliInfo( Form( "%d\t %f\t %f\t %f\t %f",
868 parameters[iDet*fgNParCh+0],parameters[iDet*fgNParCh+1],
869 parameters[iDet*fgNParCh+3],parameters[iDet*fgNParCh+2]
875 //_____________________________________________________
876 void AliMUONAlignment::PrintGlobalParameters() const
877 { fMillepede->PrintGlobalParameters(); }
879 //_____________________________________________________
880 Double_t AliMUONAlignment::GetParError(Int_t iPar) const
881 { return fMillepede->GetParError(iPar); }
883 //______________________________________________________________________
884 AliMUONGeometryTransformer* AliMUONAlignment::ReAlign(
885 const AliMUONGeometryTransformer * transformer,
886 const double *misAlignments, Bool_t )
889 /// Returns a new AliMUONGeometryTransformer with the found misalignments
892 // Takes the internal geometry module transformers, copies them
893 // and gets the Detection Elements from them.
894 // Takes misalignment parameters and applies these
895 // to the local transform of the Detection Element
896 // Obtains the global transform by multiplying the module transformer
897 // transformation with the local transformation
898 // Applies the global transform to a new detection element
899 // Adds the new detection element to a new module transformer
900 // Adds the new module transformer to a new geometry transformer
901 // Returns the new geometry transformer
903 Double_t lModuleMisAlignment[fgNParCh] = {0};
904 Double_t lDetElemMisAlignment[fgNParCh] = {0};
905 const TClonesArray* oldMisAlignArray( transformer->GetMisAlignmentData() );
907 AliMUONGeometryTransformer *newGeometryTransformer = new AliMUONGeometryTransformer();
908 for( Int_t iMt = 0; iMt < transformer->GetNofModuleTransformers(); ++iMt )
911 // module transformers
912 const AliMUONGeometryModuleTransformer *kModuleTransformer = transformer->GetModuleTransformer(iMt, kTRUE);
914 AliMUONGeometryModuleTransformer *newModuleTransformer = new AliMUONGeometryModuleTransformer(iMt);
915 newGeometryTransformer->AddModuleTransformer(newModuleTransformer);
917 // get transformation
918 TGeoHMatrix deltaModuleTransform( DeltaTransform( lModuleMisAlignment ) );
921 TGeoHMatrix moduleTransform( *kModuleTransformer->GetTransformation() );
922 TGeoHMatrix newModuleTransform( AliMUONGeometryBuilder::Multiply( deltaModuleTransform, moduleTransform ) );
923 newModuleTransformer->SetTransformation(newModuleTransform);
925 // Get matching old alignment and update current matrix accordingly
926 if( oldMisAlignArray )
929 const AliAlignObjMatrix* oldAlignObj(0);
930 const Int_t moduleId( kModuleTransformer->GetModuleId() );
931 const Int_t volId = AliGeomManager::LayerToVolUID(AliGeomManager::kMUON, moduleId );
932 for( Int_t pos = 0; pos < oldMisAlignArray->GetEntriesFast(); ++pos )
935 const AliAlignObjMatrix* localAlignObj( dynamic_cast<const AliAlignObjMatrix*>(oldMisAlignArray->At( pos ) ) );
936 if( localAlignObj && localAlignObj->GetVolUID() == volId )
938 oldAlignObj = localAlignObj;
948 TGeoHMatrix oldMatrix;
949 oldAlignObj->GetMatrix( oldMatrix );
950 deltaModuleTransform.Multiply( &oldMatrix );
956 // Create module mis alignment matrix
957 newGeometryTransformer ->AddMisAlignModule(kModuleTransformer->GetModuleId(), deltaModuleTransform);
959 AliMpExMap *detElements = kModuleTransformer->GetDetElementStore();
961 TIter next(detElements->CreateIterator());
962 AliMUONGeometryDetElement* detElement;
964 while ( ( detElement = static_cast<AliMUONGeometryDetElement*>(next()) ) )
967 // make a new detection element
968 AliMUONGeometryDetElement *newDetElement = new AliMUONGeometryDetElement(detElement->GetId(), detElement->GetVolumePath());
969 TString lDetElemName(detElement->GetDEName());
970 lDetElemName.ReplaceAll("DE","");
972 // store detector element id and number
973 const Int_t iDetElemId = lDetElemName.Atoi();
974 if( !DetElemIsValid( iDetElemId ) )
976 AliInfo( Form( "Skipping invalid detector element %i", iDetElemId ) );
980 const Int_t iDetElemNumber( GetDetElemNumber( iDetElemId ) );
982 for( int i=0; i<fgNParCh; ++i )
984 lDetElemMisAlignment[i] = 0.0;
985 if( iMt<fgNTrkMod ) { lDetElemMisAlignment[i] = misAlignments[iDetElemNumber*fgNParCh+i]; }
988 // get transformation
989 TGeoHMatrix deltaGlobalTransform( DeltaTransform( lDetElemMisAlignment ) );
992 TGeoHMatrix globalTransform( *detElement->GetGlobalTransformation() );
993 TGeoHMatrix newGlobalTransform( AliMUONGeometryBuilder::Multiply( deltaGlobalTransform, globalTransform ) );
994 newDetElement->SetGlobalTransformation( newGlobalTransform );
995 newModuleTransformer->GetDetElementStore()->Add(newDetElement->GetId(), newDetElement);
997 // Get matching old alignment and update current matrix accordingly
998 if( oldMisAlignArray )
1001 const AliAlignObjMatrix* oldAlignObj(0);
1002 const int detElemId( detElement->GetId() );
1003 const Int_t volId = AliGeomManager::LayerToVolUID(AliGeomManager::kMUON, detElemId );
1004 for( Int_t pos = 0; pos < oldMisAlignArray->GetEntriesFast(); ++pos )
1007 const AliAlignObjMatrix* localAlignObj( dynamic_cast<const AliAlignObjMatrix*>(oldMisAlignArray->At( pos ) ) );
1008 if( localAlignObj && localAlignObj->GetVolUID() == volId )
1010 oldAlignObj = localAlignObj;
1020 TGeoHMatrix oldMatrix;
1021 oldAlignObj->GetMatrix( oldMatrix );
1022 deltaGlobalTransform.Multiply( &oldMatrix );
1028 // Create misalignment matrix
1029 newGeometryTransformer->AddMisAlignDetElement(detElement->GetId(), deltaGlobalTransform);
1033 newGeometryTransformer->AddModuleTransformer(newModuleTransformer);
1036 return newGeometryTransformer;
1040 //______________________________________________________________________
1041 void AliMUONAlignment::SetAlignmentResolution( const TClonesArray* misAlignArray, Int_t rChId, Double_t chResX, Double_t chResY, Double_t deResX, Double_t deResY )
1044 /// Set alignment resolution to misalign objects to be stored in CDB
1045 /// if rChId is > 0 set parameters for this chamber only, counting from 1
1046 TMatrixDSym mChCorrMatrix(6);
1047 mChCorrMatrix[0][0]=chResX*chResX;
1048 mChCorrMatrix[1][1]=chResY*chResY;
1050 TMatrixDSym mDECorrMatrix(6);
1051 mDECorrMatrix[0][0]=deResX*deResX;
1052 mDECorrMatrix[1][1]=deResY*deResY;
1054 AliAlignObjMatrix *alignMat = 0x0;
1056 for( Int_t chId = 0; chId <= 9; ++chId )
1059 // skip chamber if selection is valid, and does not match
1060 if( rChId > 0 && chId+1 != rChId ) continue;
1067 chName1 = Form("GM%d",chId);
1068 chName2 = Form("GM%d",chId);
1072 chName1 = Form("GM%d",4+(chId-4)*2);
1073 chName2 = Form("GM%d",4+(chId-4)*2+1);
1077 for( int i=0; i<misAlignArray->GetEntries(); ++i )
1080 alignMat = (AliAlignObjMatrix*)misAlignArray->At(i);
1081 TString volName(alignMat->GetSymName());
1082 if((volName.Contains(chName1)&&
1083 ((volName.Last('/')==volName.Index(chName1)+chName1.Length())||
1084 (volName.Length()==volName.Index(chName1)+chName1.Length())))||
1085 (volName.Contains(chName2)&&
1086 ((volName.Last('/')==volName.Index(chName2)+chName2.Length())||
1087 (volName.Length()==volName.Index(chName2)+chName2.Length()))))
1090 volName.Remove(0,volName.Last('/')+1);
1091 if (volName.Contains("GM")) alignMat->SetCorrMatrix(mChCorrMatrix);
1092 else if (volName.Contains("DE")) alignMat->SetCorrMatrix(mDECorrMatrix);
1103 //_____________________________________________________
1104 void AliMUONAlignment::FillDetElemData( AliMUONVCluster* cluster )
1107 /// Get information of current detection element
1108 // get detector element number from Alice ID
1109 const Int_t detElemId = cluster->GetDetElemId();
1110 fDetElemNumber = GetDetElemNumber( detElemId );
1112 // get detector element
1113 const AliMUONGeometryDetElement* detElement = fTransform->GetDetElement( detElemId );
1116 get the global transformation matrix and store its inverse, in order to manually perform
1117 the global to Local transformations needed to calculate the derivatives
1119 fGeoCombiTransInverse = detElement->GetGlobalTransformation()->Inverse();
1123 //______________________________________________________________________
1124 void AliMUONAlignment::FillRecPointData( AliMUONVCluster* cluster )
1127 /// Get information of current cluster
1128 fClustPos[0] = cluster->GetX();
1129 fClustPos[1] = cluster->GetY();
1130 fClustPos[2] = cluster->GetZ();
1134 //______________________________________________________________________
1135 void AliMUONAlignment::FillTrackParamData( AliMUONTrackParam* trackParam )
1138 /// Get information of current track at current cluster
1139 fTrackPos[0] = trackParam->GetNonBendingCoor();
1140 fTrackPos[1] = trackParam->GetBendingCoor();
1141 fTrackPos[2] = trackParam->GetZ();
1142 fTrackSlope[0] = trackParam->GetNonBendingSlope();
1143 fTrackSlope[1] = trackParam->GetBendingSlope();
1147 //______________________________________________________________________
1148 Bool_t AliMUONAlignment::UnbiasTrackParamData( AliMUONTrackParam* trackParam ) const
1152 calculate unbiased track parameters at a given detector, that is,
1153 after taking out the contribution of the detector's cluster from the track
1156 // check track parameters
1157 if( !trackParam ) return kFALSE;
1159 // Remove cluster contibution from smoothed track param
1160 TMatrixD smoothParameters( trackParam->GetSmoothParameters() );
1161 TMatrixD smoothCovariances( trackParam->GetSmoothCovariances() );
1163 AliMUONVCluster* cluster = trackParam->GetClusterPtr();
1164 // p' = p + K(m - H*p)
1165 // K = C H (-V + H C H^t)^-1
1167 // where p,C are smoothed param,cov at cluster position
1168 // H is the matrix converting the state vector to measurement
1169 // V is the measurement cov.matrix
1170 // m is the measurement vector
1171 static TMatrixD H(2,5);
1175 // (-Vk+H_k C^n_k H_k^T)^-1
1176 static TMatrixD df(2,2);
1178 df(0,0) = smoothCovariances(0,0) - cluster->GetErrX2();
1179 df(1,1) = smoothCovariances(2,2) - cluster->GetErrY2();
1180 df(0,1) = smoothCovariances(0,2);
1181 df(1,0) = smoothCovariances(2,0);
1183 if (df.Determinant() != 0) df.Invert();
1185 AliInfo( "Determinant = 0\n" );
1190 TMatrixD kTmp( smoothCovariances, TMatrixD::kMultTranspose, H );
1191 TMatrixD K(kTmp, TMatrixD::kMult, df);
1195 dfc(0,0) = cluster->GetX()-smoothParameters(0,0);
1196 dfc(1,0) = cluster->GetY()-smoothParameters(2,0);
1197 TMatrixD tmp0(K,TMatrixD::kMult, dfc);
1198 smoothParameters += tmp0;
1200 TMatrixD tmp1(K, TMatrixD::kMult, H);
1201 TMatrixD tmp2(tmp1,TMatrixD::kMult, smoothCovariances);
1202 smoothCovariances -= tmp2;
1204 // update track parameters
1205 trackParam->SetParameters( smoothParameters );
1206 trackParam->SetCovariances( smoothCovariances );
1212 //______________________________________________________________________
1213 void AliMUONAlignment::LocalEquationX( void )
1215 /// local equation along X
1217 // 'inverse' (GlobalToLocal) rotation matrix
1218 const Double_t* r( fGeoCombiTransInverse.GetRotationMatrix() );
1220 // local derivatives
1221 SetLocalDerivative( 0, r[0] );
1222 SetLocalDerivative( 1, r[0]*(fTrackPos[2] - fTrackPos0[2]) );
1223 SetLocalDerivative( 2, r[1] );
1224 SetLocalDerivative( 3, r[1]*(fTrackPos[2] - fTrackPos0[2]) );
1226 // global derivatives
1228 alignment parameters are
1235 SetGlobalDerivative( fDetElemNumber*fgNParCh + 0, -r[0] );
1236 SetGlobalDerivative( fDetElemNumber*fgNParCh + 1, -r[1] );
1241 // use local position for derivatives vs 'delta_phi_z'
1242 SetGlobalDerivative( fDetElemNumber*fgNParCh + 2, -r[1]*fTrackPos[0] + r[0]*fTrackPos[1] );
1244 // use local slopes for derivatives vs 'delta_z'
1245 SetGlobalDerivative( fDetElemNumber*fgNParCh + 3, r[0]*fTrackSlope[0] + r[1]*fTrackSlope[1] );
1249 // local copy of extrapolated track positions
1250 const Double_t trackPosX = fTrackPos0[0]+fTrackSlope0[0]*( fTrackPos[2]-fTrackPos0[2] );
1251 const Double_t trackPosY = fTrackPos0[1]+fTrackSlope0[1]*( fTrackPos[2]-fTrackPos0[2] );
1253 // use properly extrapolated position for derivatives vs 'delta_phi_z'
1254 SetGlobalDerivative( fDetElemNumber*fgNParCh + 2, -r[1]*trackPosX + r[0]*trackPosY );
1256 // use slopes at origin for derivatives vs 'delta_z'
1257 SetGlobalDerivative( fDetElemNumber*fgNParCh + 3, r[0]*fTrackSlope0[0] + r[1]*fTrackSlope0[1] );
1261 // store local equation
1262 fMillepede->SetLocalEquation( fGlobalDerivatives, fLocalDerivatives, fMeas[0], fSigma[0] );
1266 //______________________________________________________________________
1267 void AliMUONAlignment::LocalEquationY( void )
1269 /// local equation along Y
1271 // 'inverse' (GlobalToLocal) rotation matrix
1272 const Double_t* r( fGeoCombiTransInverse.GetRotationMatrix() );
1274 // store local derivatives
1275 SetLocalDerivative( 0, r[3] );
1276 SetLocalDerivative( 1, r[3]*(fTrackPos[2] - fTrackPos0[2] ) );
1277 SetLocalDerivative( 2, r[4] );
1278 SetLocalDerivative( 3, r[4]*(fTrackPos[2] - fTrackPos0[2] ) );
1280 // set global derivatives
1281 SetGlobalDerivative( fDetElemNumber*fgNParCh + 0, -r[3]);
1282 SetGlobalDerivative( fDetElemNumber*fgNParCh + 1, -r[4]);
1287 // use local position for derivatives vs 'delta_phi'
1288 SetGlobalDerivative( fDetElemNumber*fgNParCh + 2, -r[4]*fTrackPos[0] + r[3]*fTrackPos[1]);
1290 // use local slopes for derivatives vs 'delta_z'
1291 SetGlobalDerivative( fDetElemNumber*fgNParCh + 3, r[3]*fTrackSlope[0]+r[4]*fTrackSlope[1] );
1295 // local copy of extrapolated track positions
1296 const Double_t trackPosX = fTrackPos0[0]+fTrackSlope0[0]*( fTrackPos[2]-fTrackPos0[2] );
1297 const Double_t trackPosY = fTrackPos0[1]+fTrackSlope0[1]*( fTrackPos[2]-fTrackPos0[2] );
1299 // use properly extrapolated position for derivatives vs 'delta_phi'
1300 SetGlobalDerivative( fDetElemNumber*fgNParCh + 2, -r[4]*trackPosX + r[3]*trackPosY );
1302 // use slopes at origin for derivatives vs 'delta_z'
1303 SetGlobalDerivative( fDetElemNumber*fgNParCh + 3, r[3]*fTrackSlope0[0]+r[4]*fTrackSlope0[1] );
1307 // store local equation
1308 fMillepede->SetLocalEquation( fGlobalDerivatives, fLocalDerivatives, fMeas[1], fSigma[1] );
1312 //_________________________________________________________________________
1313 TGeoCombiTrans AliMUONAlignment::DeltaTransform( const double *lMisAlignment) const
1315 /// Get Delta Transformation, based on alignment parameters
1318 const TGeoTranslation deltaTrans( lMisAlignment[0], lMisAlignment[1], lMisAlignment[3]);
1321 TGeoRotation deltaRot;
1322 deltaRot.RotateZ(lMisAlignment[2]*180./TMath::Pi());
1324 // combined rotation and translation.
1325 return TGeoCombiTrans(deltaTrans,deltaRot);
1329 //______________________________________________________________________
1330 void AliMUONAlignment::AddConstraint(Double_t *par, Double_t value)
1332 /// Constrain equation defined by par to value
1334 { AliFatal( "Millepede is not initialized" ); }
1336 fMillepede->SetGlobalConstraint(par, value);
1339 //______________________________________________________________________
1340 Bool_t AliMUONAlignment::DetElemIsValid( Int_t iDetElemId ) const
1342 /// return true if given detector element is valid (and belongs to muon tracker)
1343 const Int_t iCh = iDetElemId/100;
1344 const Int_t iDet = iDetElemId%100;
1345 return ( iCh > 0 && iCh <= fgNCh && iDet < fgNDetElemCh[iCh-1] );
1348 //______________________________________________________________________
1349 Int_t AliMUONAlignment::GetDetElemNumber( Int_t iDetElemId ) const
1351 /// get det element number from ID
1352 // get chamber and element number in chamber
1353 const Int_t iCh = iDetElemId/100;
1354 const Int_t iDet = iDetElemId%100;
1356 // make sure detector index is valid
1357 if( !( iCh > 0 && iCh <= fgNCh && iDet < fgNDetElemCh[iCh-1] ) )
1358 { AliFatal( Form( "Invalid detector element id: %i", iDetElemId ) ); }
1360 // add number of detectors up to this chamber
1361 return iDet + fgSNDetElemCh[iCh-1];
1365 //______________________________________________________________________
1366 Int_t AliMUONAlignment::GetChamberId( Int_t iDetElemNumber ) const
1368 /// get chamber (counting from 1) matching a given detector element id
1370 for( iCh=0; iCh<fgNCh; iCh++ )
1371 { if( iDetElemNumber < fgSNDetElemCh[iCh] ) break; }
1376 //______________________________________________________________________
1377 TString AliMUONAlignment::GetParameterMaskString( UInt_t mask ) const
1380 if( mask & ParX ) out += "X";
1381 if( mask & ParY ) out += "Y";
1382 if( mask & ParZ ) out += "Z";
1383 if( mask & ParTZ ) out += "T";
1387 //______________________________________________________________________
1388 TString AliMUONAlignment::GetSidesMaskString( UInt_t mask ) const
1391 if( mask & SideTop ) out += "T";
1392 if( mask & SideLeft ) out += "L";
1393 if( mask & SideBottom ) out += "B";
1394 if( mask & SideRight ) out += "R";