Fixed coverity issues
[u/mrichter/AliRoot.git] / FMD / AliFMDSurveyToAlignObjs.cxx
1 //
2 // Class to take survey data and 
3 // transform that to alignment objects. 
4 // 
5 // FMD
6 //
7 #include "AliFMDSurveyToAlignObjs.h"
8 #include "AliLog.h"
9 #include "AliSurveyPoint.h"
10 #include <TGraph2DErrors.h>
11 #include <TF2.h>
12 #include <TVector3.h>
13 #include <iostream>
14 #include <iomanip>
15 #include <TMath.h>
16 #include <TRotation.h>
17 #include <TGeoMatrix.h>
18 #include <TGeoManager.h>
19 #include <TGeoPhysicalNode.h>
20 #include "AliFMDGeometry.h"
21
22 //____________________________________________________________________
23 Double_t
24 AliFMDSurveyToAlignObjs::GetUnitFactor() const
25 {
26   // Returns the conversion factor from the measured values to
27   // centimeters. 
28   if (!fSurveyObj) return 0;
29   TString units(fSurveyObj->GetUnits());
30   if      (units.CompareTo("mm", TString::kIgnoreCase) == 0) return .1;
31   else if (units.CompareTo("cm", TString::kIgnoreCase) == 0) return 1.;
32   else if (units.CompareTo("m",  TString::kIgnoreCase) == 0) return 100.;
33   return 1;
34 }
35
36 //____________________________________________________________________
37 Bool_t
38 AliFMDSurveyToAlignObjs::GetPoint(const char* name, 
39                                   TVector3&   point, 
40                                   TVector3&   error) const
41 {
42   // Get named point.   On return, point will contain the point
43   // coordinates in centimeters, and error will contain the
44   // meassurement errors in centimeters too.  If no point is found,
45   // returns false, otherwise true. 
46   if (!fSurveyPoints) return kFALSE;
47   
48   Double_t unit = GetUnitFactor();
49   if (unit == 0) return kFALSE;
50   
51   TObject* obj  = fSurveyPoints->FindObject(name);
52   if (!obj) return kFALSE;
53   
54   AliSurveyPoint* p = static_cast<AliSurveyPoint*>(obj);
55   point.SetXYZ(unit * p->GetX(), 
56                unit * p->GetY(),
57                unit * p->GetZ());
58   error.SetXYZ(unit * p->GetPrecisionX(),
59                unit * p->GetPrecisionY(),
60                unit * p->GetPrecisionZ());
61   return kTRUE;
62 }
63
64 //____________________________________________________________________
65 Bool_t 
66 AliFMDSurveyToAlignObjs::CalculatePlane(const     TVector3& a, 
67                                         const     TVector3& b,
68                                         const     TVector3& c, 
69                                         Double_t  depth,
70                                         Double_t* trans,
71                                         Double_t* rot) const
72 {
73   // 
74   // Calculate the plane translation and rotation from 3 survey points
75   // 
76   // Parameters:
77   //    a     1st Survey point 
78   //    b     2nd Survey point
79   //    c     3rd Survey point
80   //    trans Translation vector
81   //    rot   Rotation matrix (direction cosines)
82   // 
83   // Return:
84   //    
85   //
86
87   // Vector a->b, b->c, and normal to plane defined by these two
88   // vectors. 
89   TVector3 ab(b-a), bc(c-a);
90   
91   // Normal vector to the plane of the fiducial marks obtained
92   // as cross product of the two vectors on the plane d0^d1
93   TVector3 nn(ab.Cross(bc));
94   if (nn.Mag() < 1e-8) { 
95     Info("CalculatePlane", "Normal vector is null vector");
96     return kFALSE;
97   }
98   
99   // We express the plane in Hessian normal form.
100   //
101   //   n x = -p,
102   //
103   // where n is the normalised normal vector given by 
104   // 
105   //   n_x = a / l,   n_y = b / l,   n_z = c / l,  p = d / l
106   //
107   // with l = sqrt(a^2+b^2+c^2) and a, b, c, and d are from the
108   // normal plane equation 
109   //
110   //  ax + by + cz + d = 0
111   // 
112   // Normalize
113   TVector3 n(nn.Unit());
114   // Double_t p = - (n * a);
115   
116   // The center of the square with the fiducial marks as the
117   // corners.  The mid-point of one diagonal - md.  Used to get the
118   // center of the surveyd box. 
119   // TVector3 md(a + c);
120   // md *= 1/2.;
121   //Info("CalculatePlane", "corner=(%8f,%8f,%8f)", c.X(),c.Y(),c.Z());
122   //Info("CalculatePlane", "corner=(%8f,%8f,%8f)", b.X(),b.Y(),b.Z());
123   TVector3 md(c + b);
124   md *= 1./2;
125   //Info("CalculatePlane", "mid=(%8f,%8f,%8f)", md.X(),md.Y(),md.Z());
126   //Info("CalculatePlane", "normal=(%8f,%8f,%8f)", n.X(),n.Y(),n.Z());
127
128   // The center of the box. 
129   TVector3 orig(md - depth * n);
130   // Info("CalculatePlane", "orig=(%8f,%8f,%8f)", orig.X(),orig.Y(),orig.Z());
131   trans[0] = orig[0];
132   trans[1] = orig[1];
133   trans[2] = orig[2];
134   //Info("CalculatePlane", "trans=(%8f,%8f,%8f)", trans[0],trans[1],trans[2]);
135   
136   // Normalize the spanning vectors 
137   TVector3 uab(ab.Unit());
138   TVector3 ubc(bc.Unit());
139   
140   for (size_t i = 0; i < 3; i++) { 
141     rot[i * 3 + 0] = ubc[i];
142     rot[i * 3 + 1] = uab[i];
143     // rot[i * 3 + 0] = uab[i];
144     // rot[i * 3 + 1] = ubc[i];
145     rot[i * 3 + 2] = n[i];
146   }
147   return kTRUE;
148 }
149
150 //____________________________________________________________________
151 Bool_t 
152 AliFMDSurveyToAlignObjs::FitPlane(const TObjArray& points, 
153                                   const TObjArray& errors,
154                                   Double_t         /* depth */,
155                                   Double_t*        trans,
156                                   Double_t*        rot) const
157 {
158   // 
159   // Calculate the plane rotation and translation by doing a fit of
160   // the plane equation to the surveyed points.  At least 4 points
161   // must be passed in the @a points array with corresponding errors
162   // in the array @a errors.  The arrays are assumed to contain
163   // TVector3 objects.
164   // 
165   // Parameters:
166   //    points Array surveyed positions
167   //    errors Array of errors corresponding to @a points
168   //    depth  Survey targets depth (perpendicular to the plane)
169   //    trans  On return, translation of the plane
170   //    rot    On return, rotation (direction cosines) of the plane
171   // 
172   // Return:
173   //    @c true on success, @c false otherwise
174   //
175
176   Int_t nPoints = points.GetEntries();
177   if (nPoints < 4) { 
178     AliError(Form("Cannot fit a plane equation to less than 4 survey points, "
179                   "got only %d", nPoints));
180     return kFALSE;
181   }
182   
183   TGraph2DErrors g;
184   // Loop and fill graph 
185   for (int i = 0; i < nPoints; i++) {
186     TVector3* p = static_cast<TVector3*>(points.At(i));
187     TVector3* e = static_cast<TVector3*>(errors.At(i));
188   
189     if (!p || !e) continue;
190     
191     g.SetPoint(i, p->X(), p->Y(), p->Z());
192     g.SetPointError(i, e->X(), e->Y(), e->Z());
193
194   }
195
196   // Check that we have enough points
197   if (g.GetN() < 4) { 
198     AliError(Form("Only got %d survey points - no good for plane fit",
199                   g.GetN()));
200     return kFALSE;
201   }
202
203   // Next, declare fitting function and fit to graph. 
204   // Fit to the plane equation: 
205   // 
206   //   ax + by + cz + d = 0
207   //
208   // or 
209   // 
210   //   z = - ax/c - by/c - d/c
211   //
212   TF2 f("plane", "-[0]*x-[1]*y-[2]", 
213         g.GetXmin(), g.GetXmax(), g.GetYmin(), g.GetYmax());
214   g.Fit(&f, "Q");
215   
216   // Now, extract the normal and offset
217   TVector3 nv(f.GetParameter(0), f.GetParameter(1), 1);
218   TVector3 n(nv.Unit());
219   Double_t p = -f.GetParameter(2);
220   
221   // Create two vectors spanning the plane 
222   TVector3 a(1, 0, f.Eval(1, 0)-p);
223   TVector3 b(0, -1, f.Eval(0, -1)-p);
224   TVector3 ua(a.Unit());
225   TVector3 ub(b.Unit());
226   // Double_t angAb = ua.Angle(ub);
227   // PrintVector("ua: ", ua);
228   // PrintVector("ub: ", ub);
229   // std::cout << "Angle: " << angAb * 180 / TMath::Pi() << std::endl;
230     
231   for (size_t i = 0; i < 3; i++) { 
232     rot[i * 3 + 0] = ua[i];
233     rot[i * 3 + 1] = ub[i];
234     rot[i * 3 + 2] = n[i];
235   }
236     
237   // The intersection of the plane is given by (0, 0, -d/c)
238   trans[0] = 0;
239   trans[1] = 0;
240   trans[2] = p;
241   
242   return kTRUE;
243 }
244
245
246 //____________________________________________________________________
247 Bool_t
248 AliFMDSurveyToAlignObjs::MakeDelta(const char*  path, 
249                                    const Double_t*    rot, 
250                                    const Double_t*    trans, 
251                                    TGeoHMatrix& delta) const
252 {
253   // 
254   // Create a delta transform from a global rotation matrix and
255   // translation. 
256   // 
257   // Parameters:
258   //    path   Path of element to transform.
259   //    rot    Rotation matrix (direction cosines)
260   //    trans  Translation 
261   //    delta  On return, the delta transform
262   // 
263   // Return:
264   //    Newly 
265   //
266   if (!gGeoManager)           return kFALSE;
267   if (!gGeoManager->cd(path)) return kFALSE;
268   
269   
270   TGeoMatrix*  global = gGeoManager->GetCurrentMatrix();
271 #if 0
272   PrintRotation(Form("%s rot:", global->GetName()),global->GetRotationMatrix());
273   PrintVector(Form("%s trans:", global->GetName()),global->GetTranslation());
274 #endif
275
276   return MakeDelta(global, rot, trans, delta);
277 }
278
279 //____________________________________________________________________
280 Bool_t
281 AliFMDSurveyToAlignObjs::MakeDelta(const TGeoMatrix*  global,
282                                    const Double_t*    rot, 
283                                    const Double_t*    trans, 
284                                    TGeoHMatrix& delta) const
285 {
286   // 
287   // Create a delta transform from a global rotation matrix and
288   // translation. 
289   // 
290   // Parameters:
291   //    global Global matrix of element to transform.
292   //    rot    Rotation matrix (direction cosines)
293   //    trans  Translation 
294   //    delta  On return, the delta transform
295   // 
296   // Return:
297   //    Newly 
298   //
299   TGeoHMatrix* geoM = new TGeoHMatrix;
300   geoM->SetTranslation(trans);
301   geoM->SetRotation(rot);
302   // Info("MakeDelta", "The HMatrix from survey");
303   // geoM->Print();
304   // Info("MakeDelta", "The global matrix");
305   // global->Print();
306
307   delta = global->Inverse();
308   // Info("MakeDelta", "The inverse global matrix");
309   // delta.Print();
310   delta.MultiplyLeft(geoM);
311   // Info("MakeDelta", "The delta matrix");
312   // delta.Print();
313   return true;
314 }
315
316 namespace {
317   Double_t getFMD1Offset()
318   {
319     static Double_t off = 0;
320     return off;
321
322 #if 0
323     if (off != 0) return off;
324     
325     const char* lidN = "FMD1_lid_mat0";
326     TGeoMatrix* lidM = static_cast<TGeoMatrix*>(gGeoManager->GetListOfMatrices()
327                                                 ->FindObject(lidN));
328     if (!lidM) { 
329       Error("getFMD1Offset", "Couldn't find FMD1 lid transformation %s", lidN);
330       return 0;
331     }
332
333     const Double_t* lidT = lidM->GetTranslation();
334     Double_t        lidZ = lidT[2];
335     off                  = lidZ-3.3;
336     
337     return off;
338 #endif
339   }
340 }
341
342 //____________________________________________________________________
343 Bool_t
344 AliFMDSurveyToAlignObjs::GetFMD1Plane(Double_t* rot, Double_t* trans) const
345 {
346   // 
347   // Get the FMD1 plane from the survey points
348   // 
349   // Parameters:
350   //    rot    Rotation matrix (direction cosines)
351   //    trans  Translation
352   // 
353   // Return:
354   //    @c true on success, @c false otherwise.
355   //
356
357   // The possile survey points 
358   TVector3  icb, ict, ocb, oct, eicb, eict, eocb, eoct;
359   Int_t     missing = 0;
360   if (!GetPoint("V0L_ICB", icb, eicb)) missing++;
361   if (!GetPoint("V0L_ICT", ict, eict)) missing++;
362   if (!GetPoint("V0L_OCB", ocb, eocb)) missing++;
363   if (!GetPoint("V0L_OCT", oct, eoct)) missing++;
364
365   // Check that we have enough points
366   if (missing > 1) { 
367     AliWarning(Form("Only got %d survey points - no good for FMD1 plane",
368                     4-missing));
369     return kFALSE;
370   }
371 #if 0
372   TObjArray points;
373   TObjArray errors;
374   points.Add(&icb); errors.Add(&eicb);
375   points.Add(&ict); errors.Add(&eict);
376   points.Add(&oct); errors.Add(&eoct);
377   points.Add(&ocb); errors.Add(&eocb);
378   
379   Bool_t ret = FitPlane(points, errors, 0, trans, rot);
380   if (!ret) { 
381     Warning("GetFMD1Plane", "fit to plane failed");
382   }
383   for (Int_t i = 0; i < 4; i++) { 
384     TVector3* v = static_cast<TVector3*>(points.At(i));
385     TVector3* e = static_cast<TVector3*>(errors.At(i));
386     Info("GetFMD1Plane", "p%d=(%8f,%8f,%8f)+/-(%8f,%8f,%8f)", 
387          i, v->X(), v->Y(), v->Z(), e->X(), e->Y(), e->Z());
388   }
389 #else
390   Double_t off = getFMD1Offset();
391   Info("GetFMD1Plane", "Lid offset is %f", off);
392
393   // if (!CalculatePlane(ocb, icb, ict, off, trans, rot)) return kFALSE;
394   // Bool_t ret = CalculatePlane(ocb, icb, oct, off, trans, rot);
395   Bool_t ret = CalculatePlane(oct, ocb, ict, off, trans, rot);
396 #endif
397   PrintRotation("FMD1 rotation:",  rot);
398   PrintVector("FMD1 translation:", trans);
399
400   return ret;
401 }
402
403 //____________________________________________________________________
404 Bool_t
405 AliFMDSurveyToAlignObjs::DoFMD1()
406 {
407   // 
408   // Do the FMD1 analysis.  We have 4 survey targets on V0-A on the
409   // C-side.  These are 
410   //
411   //  - V0A_ICT  In-side, C-side, top.
412   //  - V0A_ICB  In-side, C-side, bottom.  
413   //  - V0A_OCT  Out-side, C-side, top.  
414   //  - V0A_OCB  Out-side, C-side, bottom.
415   // 
416   // These 4 survey targets sit 3.3mm over the V0-A C-side surface, or
417   // 3.3mm over the back surface of FMD1.  
418   //
419   // Since these are really sitting on a plane, we can use the method
420   // proposed by the CORE offline. 
421   // 
422   // Return:
423   //    @c true on success, @c false otherwise.
424   //
425
426   // Do the FMD1 stuff
427   Double_t rot[9], trans[3];
428   if (!GetFMD1Plane(rot, trans)) return kFALSE;
429   // const char* path = "/ALIC_1/F1MT_1/FMD1_lid_0";
430
431 #if 0  
432   // TGeoHMatrix delta;
433   Double_t gRot[9], gTrans[3];
434   TVector3 ocb(-127, -220, 324.67);
435   TVector3 oct(-127, +220, 324.67);
436   TVector3 icb(+127, -220, 324.67);
437   TVector3 ict(+127, +220, 324.67);
438   if (!CalculatePlane(ocb, icb, oct, 0, gTrans, gRot)) { 
439     Warning("DoFMD1", "Failed to make reference plane");
440     return kFALSE;
441   }
442   PrintRotation("FMD1 ref rotation:",  gRot);
443   PrintVector("FMD1 ref translation:", gTrans);
444   TGeoRotation ggRot; ggRot.SetMatrix(gRot);
445   TGeoCombiTrans global(gTrans[0], gTrans[1], gTrans[2], &ggRot);
446 #endif
447   Double_t off = getFMD1Offset();
448   Info("DoFMD1", "Lid offset is %f", off);
449
450   TGeoTranslation global(0,0,324.670-off);
451   if (!MakeDelta(&global, rot, trans, fFMD1Delta)) 
452     return kFALSE;
453   
454   // PrintRotation("FMD1 delta rotation:",  fFMD1Delta.GetRotationMatrix());
455   // PrintVector("FMD1 delta translation:", fFMD1Delta.GetTranslation());
456
457   return kTRUE;
458 }
459
460 //____________________________________________________________________
461 Bool_t
462 AliFMDSurveyToAlignObjs::GetFMD2Plane(Double_t* rot, Double_t* trans) const
463 {
464   // 
465   // Get the surveyed plane corresponding to the backside of FMD2.
466   // The plane is done as a best fit of the plane equation to at least
467   // 4 of the available survey points.
468   // 
469   // Parameters:
470   //    rot    Rotation matrix (direction cosines)
471   //    trans  Translation vector.
472   // 
473   // Return:
474   //    @c true on success, @c false otherwise
475   //
476
477   // The possible survey points 
478   const char*    names[] = { "FMD2_ITOP",  "FMD2_OTOP", 
479                              "FMD2_IBOTM", "FMD2_OBOTM", 
480                              "FMD2_IBOT",  "FMD2_OBOT", 
481                              0 };
482   const char**   name    = names;
483
484   TObjArray points;
485   TObjArray errors;
486   
487   // Loop and fill graph 
488   int i = 0;
489   while (*name) {
490     TVector3 p, e;
491     if (!GetPoint(*name, p, e)) {
492       name++;
493       i++;
494       continue;
495     }
496     
497     if (i == 5) {
498       Warning("GetFMD2plane", "Setting error on %d, %s to 0.4", i, *name);
499       e.SetXYZ(0.4, 0.4, 0.4); // OBOT
500     }
501     points.Add(new TVector3(p));
502     errors.Add(new TVector3(e));
503     name++;
504     i++;
505   }
506   if (points.GetEntries() < 4) { 
507     AliWarning(Form("Only got %d survey points - no good for FMD2 plane",
508                     points.GetEntries()));
509     return kFALSE;
510   }
511
512   return FitPlane(points, errors, 0, trans, rot);
513 }
514
515 #define M(I,J) rot[(J-1) * 3 + (I-1)]
516 //____________________________________________________________________
517 Bool_t
518 AliFMDSurveyToAlignObjs::DoFMD2()
519 {
520   // 
521   // Do the FMD2 calculations.  We have 6 survey points of which only
522   // 5 are normally surveyed.  These are all sittings 
523   //
524   //  - FMD2_ITOP   - In-side, top
525   //  - FMD2_IBOTM  - In-side, middle bottom
526   //  - FMD2_IBOT   - In-side, bottom
527   //  - FMD2_OTOP   - Out-side, top
528   //  - FMD2_OBOTM  - Out-side, middle bottom
529   //  - FMD2_OBOT   - Out-side, bottom
530   //
531   // The nominal coordinates of these retro-fitted survey stickers
532   // isn't known.  Also, these stickers are put on a thin (0.3mm
533   // thick) carbon cover which flexes quite easily.  This means, that
534   // to rotations and xy-translation obtained from the survey data
535   // cannot be used, and left is only the z-translation.
536   //
537   // Further more, since FMD2 to is attached to the ITS SPD thermal
538   // screen, it is questionable if the FMD2 survey will ever be used. 
539   // 
540   // Return:
541   //    @c true on success, @c false otherwise.
542   //
543
544   // Do the FMD2 stuff
545   Double_t rot[9], trans[3];
546   if (!GetFMD2Plane(rot, trans)) return kFALSE;
547   PrintRotation("FMD2 rotation:",  rot);
548   PrintVector("FMD2 translation:", trans);
549
550 #if 0
551   for (int i = 0; i < 3; i++) { 
552     for (int j = 0; j < 3; j++) { 
553       rot[i*3+j] = (i == j ? 1 : 0);
554     }
555   }
556 #endif
557   trans[0] = trans[1] = 0;
558   trans[2] += 0.015;
559   // PrintRotation("FMD2 rotation:",  rot);
560   // PrintVector("FMD2 translation:", trans);
561   
562   // TGeoHMatrix delta;
563   if (!MakeDelta("/ALIC_1/F2MT_2/FMD2_support_0/FMD2_back_cover_2", 
564                  rot, trans, fFMD2Delta)) return kFALSE;
565   
566   // PrintRotation("FMD2 delta rotation:",  fFMD2Delta.GetRotationMatrix());
567   // PrintVector("FMD2 delta translation:", fFMD2Delta.GetTranslation());
568
569   return kTRUE;
570 }
571
572 //____________________________________________________________________
573 void
574 AliFMDSurveyToAlignObjs::Run()
575 {
576   // 
577   // Run the task.
578   // 
579   //  
580
581   AliFMDGeometry* geom = AliFMDGeometry::Instance();
582   geom->Init();
583   geom->InitTransformations();
584   
585   DoFMD1();
586   DoFMD2();
587 }
588
589 //____________________________________________________________________
590 void
591 AliFMDSurveyToAlignObjs::Run(const char** files)
592 {
593   // 
594   // Run the task.
595   // 
596   //  
597
598   AliFMDGeometry* geom = AliFMDGeometry::Instance();
599   geom->Init();
600   geom->InitTransformations();
601
602   const char** file = files; 
603   while (*file) { 
604     if ((*file)[0] == '\0') { 
605       Warning("Run", "no file specified");
606       file++;
607       continue;
608     }
609     if (!LoadSurveyFromLocalFile(*file)) { 
610       Warning("Run", "Failed to load %s", *file);
611       file++;
612       continue;
613     }
614     TString sDet(fSurveyObj->GetDetector());
615     Int_t   d    = Int_t(sDet[sDet.Length()-1] - '0');
616     Info("Run", "Making alignment for %s (%d)", sDet.Data(), d);
617     Bool_t ret = true;
618     switch (d) { 
619     case 1: ret = DoFMD1(); break;
620     case 2: ret = DoFMD2(); break;
621     default: 
622       Warning("Run", "Do not know how to deal with %s", sDet.Data());
623       break;
624     }
625     if (!ret) { 
626       Warning("Run", "Calculation for %s failed", sDet.Data());
627     }
628     file++;
629   }
630   CreateAlignObjs();
631   GetAlignObjArray()->Print();
632   FillDefaultAlignObjs();
633 }
634
635 //____________________________________________________________________
636 AliAlignObjParams*
637 AliFMDSurveyToAlignObjs::CreateDefaultAlignObj(const TString& path, 
638                                                Int_t id)
639 {
640   Int_t nAlign = fAlignObjArray->GetEntries();
641   AliAlignObjParams* obj = 
642     new ((*fAlignObjArray)[nAlign]) AliAlignObjParams(path.Data(),
643                                                       id,0,0,0,0,0,0,kTRUE);
644   if (!obj) {
645     AliError(Form("Failed to create alignment object for %s", path.Data()));
646     return 0;
647   }
648   if (!obj->SetLocalPars(0, 0, 0, 0, 0, 0)) {
649     AliError(Form("Failed to set local transforms on %s", path.Data()));
650     return obj;
651   }
652   return obj;
653 }
654
655 //____________________________________________________________________
656 AliAlignObjParams*
657 AliFMDSurveyToAlignObjs::FindAlignObj(const TString& path) const 
658 {
659   AliAlignObjParams* p = 0;
660   for (int i = 0; i < fAlignObjArray->GetEntries(); i++) { 
661     p = static_cast<AliAlignObjParams*>(fAlignObjArray->At(i));
662     if (path.EqualTo(p->GetSymName())) return p;
663   }
664   return 0;
665 }
666
667 //____________________________________________________________________
668 Bool_t 
669 AliFMDSurveyToAlignObjs::FillDefaultAlignObjs()
670 {
671   for (int d = 1; d <= 3; d++) { 
672     const char sides[] = { 'T', 'B', 0 };
673     const char* side   = sides;
674     while (*side) { 
675       TString path = TString::Format("FMD/FMD%d_%c", d, *side);
676       if (!FindAlignObj(path)) CreateDefaultAlignObj(path, 0);
677
678       const char halves[] = { 'I', d == 1 ? '\0' : 'O', 0 };
679       const char*  half = halves;
680       while (*half) { 
681         int nsec  = *half == 'I' ? 10 : 20;
682         int start = *side == 'T' ? 0      : nsec/2;
683         int end   = *side == 'T' ? nsec/2 : nsec;
684         for (int s=start; s < end; s++) {
685           path = TString::Format("FMD/FMD%d_%c/FMD%c_%02d", 
686                                  d, *side, *half, s);
687           CreateDefaultAlignObj(path, 0);
688         }
689         half++;
690       }
691       side++;
692     }
693     
694   }
695   return true;
696 }
697
698 //____________________________________________________________________
699 Bool_t 
700 AliFMDSurveyToAlignObjs::CreateAlignObjs()
701 {
702   // 
703   // 
704   // Method to create the alignment objects
705   // 
706   // Return:
707   //    @c true on success, @c false otherwise
708   //  
709   TClonesArray& array = *fAlignObjArray;
710   Int_t         n     = array.GetEntriesFast();
711
712   if (!fFMD1Delta.IsIdentity()) { 
713     new (array[n++]) AliAlignObjParams("FMD/FMD1_T", 0, fFMD1Delta, kTRUE);
714     new (array[n++]) AliAlignObjParams("FMD/FMD1_B", 0, fFMD1Delta, kTRUE);
715   }
716   if (!fFMD2Delta.IsIdentity()) { 
717     new (array[n++]) AliAlignObjParams("FMD/FMD2_T", 0, fFMD2Delta, kTRUE);
718     new (array[n++]) AliAlignObjParams("FMD/FMD2_B", 0, fFMD2Delta, kTRUE);
719   }
720   // array.Print();
721   
722   return kTRUE;
723 }
724
725 //____________________________________________________________________
726 void 
727 AliFMDSurveyToAlignObjs::PrintVector(const char* text, const TVector3& v)
728 {
729   // 
730   // Service member function to print a vector
731   // 
732   // Parameters:
733   //    text Prefix text
734   //    v    Vector
735   //
736   Double_t va[] = { v.X(), v.Y(), v.Z() };
737   PrintVector(text, va);
738 }
739 //____________________________________________________________________
740 void 
741 AliFMDSurveyToAlignObjs::PrintVector(const char* text, const Double_t* v)
742 {
743   // 
744   // Service member function to print a vector
745   // 
746   // Parameters:
747   //    text Prefix text
748   //    v    Vector (array of 3 doubles)
749   //
750   std::cout << text 
751             << std::setw(15) << v[0] 
752             << std::setw(15) << v[1]
753             << std::setw(15) << v[2]
754             << std::endl;
755 }
756
757
758 //____________________________________________________________________
759 void 
760 AliFMDSurveyToAlignObjs::PrintRotation(const char* text, const Double_t* rot)
761 {
762   // 
763   // Service member function to print a rotation matrix
764   // 
765   // Parameters:
766   //    text Prefix text
767   //    v    Matrix (array of 9 doubles)
768   //
769
770   std::cout << text << std::endl;
771   for (size_t i = 0; i < 3; i++) { 
772     for (size_t j = 0; j < 3; j++) 
773       std::cout << std::setw(15) << rot[i * 3 + j];
774     std::cout << std::endl;
775   }
776 }
777
778 //____________________________________________________________________
779 //
780 // EOF
781 //