]> git.uio.no Git - u/mrichter/AliRoot.git/blob - FMD/AliFMD.cxx
Fixed some coding convention violations
[u/mrichter/AliRoot.git] / FMD / AliFMD.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //////////////////////////////////////////////////////////////////////////////
19 //                                                                          
20 // Forward Multiplicity Detector based on Silicon wafers. This class
21 // contains the base procedures for the Forward Multiplicity detector
22 // Detector consists of 5 Si volumes covered pseudorapidity interval
23 // from 1.7 to 5.1.
24 //                                                       
25 // This is the base class for all FMD manager classes. 
26 //                    
27 // The actual code is done by various separate classes.   Below is
28 // diagram showing the relationship between the various FMD classes
29 // that handles the geometry 
30 //
31 //
32 //       +----------+   +----------+   
33 //       | AliFMDv1 |   | AliFMDv1 |   
34 //       +----------+   +----------+   
35 //            |              |
36 //       +----+--------------+
37 //       |
38 //       |           +------------+ 1  +---------------+
39 //       |        +- | AliFMDRing |<>--| AliFMDPolygon | 
40 //       V     2  |  +------------+    +---------------+   
41 //  +--------+<>--+        |
42 //  | AliFMD |             ^                       
43 //  +--------+<>--+        V 1..2                     
44 //             3  | +-------------------+ 
45 //                +-| AliFMDSubDetector | 
46 //                  +-------------------+
47 //                           ^              
48 //                           |
49 //             +-------------+-------------+
50 //             |             |             |          
51 //        +---------+   +---------+   +---------+
52 //        | AliFMD1 |   | AliFMD2 |   | AliFMD3 |
53 //        +---------+   +---------+   +---------+
54 //      
55 //
56 // *  AliFMD 
57 //    This defines the interface for the various parts of AliROOT that
58 //    uses the FMD, like AliFMDDigitizer, AliFMDReconstructor, and so
59 //    on. 
60 //
61 // *  AliFMDv1 
62 //    This is a concrete implementation of the AliFMD interface. 
63 //    It is the responsibility of this class to create the FMD
64 //    geometry, process hits in the FMD, and serve hits and digits to
65 //    the various clients. 
66 //  
67 //    It uses the objects of class AliFMDSubDetector to do the various
68 //    stuff for FMD1, 2, and 3 
69 //
70 // *  AliFMDRing 
71 //    This class contains all stuff needed to do with a ring.  It's
72 //    used by the AliFMDSubDetector objects to instantise inner and
73 //    outer rings.  The AliFMDRing objects are shared by the
74 //    AliFMDSubDetector objects, and owned by the AliFMDv1 object. 
75 //
76 // *  AliFMDPolygon 
77 //    The code I lifted from TGeoPolygon to help with the geometry of
78 //    the modules, as well as to decide wether a hit is actually with
79 //    in the real module shape.  The point is, that the shape of the
80 //    various ring modules are really polygons (much like the lid of a
81 //    coffin), but it's segmented at constant radius.  That is very
82 //    hard to implement using GEANT 3.21 shapes, so instead the
83 //    modules are implemented as TUBS (tube sections), and in the step
84 //    procedure we do the test whether the track was inside the real
85 //    shape of the module.  
86 //
87 // *  AliFMD1, AliFMD2, and AliFMD3 
88 //    These are specialisation of AliFMDSubDetector, that contains the
89 //    particularities of each of the sub-detector system.  It is
90 //    envisioned that the classes should also define the support
91 //    volumes and material for each of the detectors.                          
92 //                                                                          
93 // The responsible person for this module is Alla Maevskaia
94 // <Alla.Maevskaia@cern.ch>.
95 //
96 // Many modifications by Christian Holm Christensen <cholm@nbi.dk>
97 //
98
99 #ifndef ROOT_TClonesArray
100 #include <TClonesArray.h>
101 #endif
102 #ifndef ROOT_TGeomtry
103 # include <TGeometry.h>
104 #endif
105 #ifndef ROOT_TNode
106 # include <TNode.h>
107 #endif
108 #ifndef ROOT_TTUBE
109 # include <TTUBE.h>
110 #endif
111 #ifndef ROOT_TTree
112 # include <TTree.h>
113 #endif
114 #ifndef ROOT_TVirtualMC
115 # include <TVirtualMC.h>
116 #endif
117 #ifndef ROOT_TBrowser
118 # include <TBrowser.h>
119 #endif
120 #ifndef ROOT_TMath
121 # include <TMath.h>
122 #endif
123
124 #ifndef ALIRUNDIGITIZER_H
125 # include "AliRunDigitizer.h"
126 #endif
127 #ifndef ALILOADER_H
128 # include "AliLoader.h"
129 #endif
130 #ifndef ALIRUN_H
131 # include "AliRun.h"
132 #endif
133 #ifndef ALIMC_H
134 # include "AliMC.h"
135 #endif
136 #ifndef ALILOG_H
137 # include "AliLog.h"
138 #endif
139 #ifndef ALIMAGF_H
140 # include "AliMagF.h"
141 #endif
142 #ifndef ALIFMD_H
143 # include "AliFMD.h"
144 #endif
145 #ifndef ALIFMDDIGIG_H
146 # include "AliFMDDigit.h"
147 #endif
148 #ifndef ALIFMDHIT_H
149 # include "AliFMDHit.h"
150 #endif
151 #ifndef ALIFMDDIGITIZER_H
152 # include "AliFMDDigitizer.h"
153 #endif
154 #ifndef ALIFMD1_H
155 # include "AliFMD1.h"
156 #endif
157 #ifndef ALIFMD2_H
158 # include "AliFMD2.h"
159 #endif
160 #ifndef ALIFMD3_H
161 # include "AliFMD3.h"
162 #endif
163 #ifndef ALIALTROBUFFER_H
164 # include "AliAltroBuffer.h"
165 #endif
166
167 //____________________________________________________________________
168 ClassImp(AliFMD);
169
170 //____________________________________________________________________
171 AliFMD::AliFMD()
172   : fInner(0), 
173     fOuter(0),
174     fFMD1(0),
175     fFMD2(0), 
176     fFMD3(0)
177 {
178   //
179   // Default constructor for class AliFMD
180   //
181   AliDebug(0, "Default CTOR");
182   fHits     = 0;
183   fDigits   = 0;
184   fSDigits  = 0;
185   fNsdigits = 0;
186   fIshunt   = 0;
187 }
188
189 //____________________________________________________________________
190 AliFMD::AliFMD(const char *name, const char *title, bool detailed)
191   : AliDetector (name, title),
192     fInner(0), 
193     fOuter(0),
194     fFMD1(0),
195     fFMD2(0), 
196     fFMD3(0)
197 {
198   //
199   // Standard constructor for Forward Multiplicity Detector
200   //
201   AliDebug(0, "Standard CTOR");
202
203   // Initialise Hit array
204   HitsArray();
205   gAlice->GetMCApp()->AddHitList(fHits);
206
207   // (S)Digits for the detectors disk
208   DigitsArray();
209   SDigitsArray();
210   
211   // CHC: What is this?
212   fIshunt = 0;
213   SetMarkerColor(kRed);
214   SetLineColor(kYellow);
215   SetSiDensity();
216
217   // Create sub-volume managers 
218   fInner = new AliFMDRing('I', detailed);
219   fOuter = new AliFMDRing('O', detailed);
220   fFMD1  = new AliFMD1();
221   fFMD2  = new AliFMD2();
222   fFMD3  = new AliFMD3();
223
224   // Specify parameters of sub-volume managers 
225   fFMD1->SetInner(fInner);
226   fFMD1->SetOuter(0);
227
228   fFMD2->SetInner(fInner);
229   fFMD2->SetOuter(fOuter);
230   
231   fFMD3->SetInner(fInner);
232   fFMD3->SetOuter(fOuter);
233
234   SetLegLength();
235   SetLegRadius();
236   SetLegOffset();
237   SetModuleSpacing();
238   
239   fInner->SetLowR(4.3);
240   fInner->SetHighR(17.2);
241   fInner->SetWaferRadius(13.4/2);
242   fInner->SetTheta(36/2);
243   fInner->SetNStrips(512);
244   fInner->SetSiThickness(.03);
245   fInner->SetPrintboardThickness(.11);
246   fInner->SetBondingWidth(.5);
247
248   fOuter->SetLowR(15.6);
249   fOuter->SetHighR(28.0);
250   fOuter->SetWaferRadius(13.4/2);
251   fOuter->SetTheta(18/2);
252   fOuter->SetNStrips( 256);
253   fOuter->SetSiThickness(.03);
254   fOuter->SetPrintboardThickness(.1);
255   fOuter->SetBondingWidth(.5);
256   
257   
258   fFMD1->SetHoneycombThickness(1);
259   fFMD1->SetInnerZ(340.0);
260   
261   fFMD2->SetHoneycombThickness(1);
262   fFMD2->SetInnerZ(83.4);
263   fFMD2->SetOuterZ(75.2);
264
265   fFMD3->SetHoneycombThickness(1);
266   fFMD3->SetInnerZ(-62.8);
267   fFMD3->SetOuterZ(-75.2);
268 }
269
270 //____________________________________________________________________
271 AliFMD::~AliFMD ()
272 {
273   // Destructor for base class AliFMD
274   if (fHits) {
275     fHits->Delete();
276     delete fHits;
277     fHits = 0;
278   }
279   if (fDigits) {
280     fDigits->Delete();
281     delete fDigits;
282     fDigits = 0;
283   }
284   if (fSDigits) {
285     fSDigits->Delete();
286     delete fSDigits;
287     fSDigits = 0;
288   }
289 }
290
291 //====================================================================
292 //
293 // GEometry ANd Traking
294 //
295 //____________________________________________________________________
296 void 
297 AliFMD::CreateGeometry()
298 {
299   //
300   // Create the geometry of Forward Multiplicity Detector.  The actual
301   // construction of the geometry is delegated to the class AliFMDRing
302   // and AliFMDSubDetector and the relevant derived classes. 
303   //
304   // The flow of this member function is:
305   //
306   //   FOR rings fInner and fOuter DO  
307   //     AliFMDRing::Init();
308   //   END FOR
309   // 
310   //   Set up hybrud card support (leg) volume shapes  
311   // 
312   //   FOR rings fInner and fOuter DO  
313   //     AliFMDRing::SetupGeometry();
314   //   END FOR
315   // 
316   //   FOR subdetectors fFMD1, fFMD2, and fFMD3 DO 
317   //     AliFMDSubDetector::SetupGeomtry();
318   //   END FOR
319   // 
320   //   FOR subdetectors fFMD1, fFMD2, and fFMD3 DO 
321   //     AliFMDSubDetector::Geomtry();
322   //   END FOR
323   //   
324
325   // DebugGuard guard("AliFMD::CreateGeometry");
326   AliDebug(10, "Creating geometry");
327
328   fInner->Init();
329   fOuter->Init();
330
331   TString name;
332   Double_t par[3];
333
334   par[0]      =  fLegRadius - .1;
335   par[1]      =  fLegRadius;
336   par[2]      =  fLegLength / 2;
337   name        =  "FSL";
338   fShortLegId =  gMC->Gsvolu(name.Data(),"TUBE",(*fIdtmed)[kPlasticId],par,3);
339   
340   par[2]      += fModuleSpacing / 2;
341   name        = "FLL";
342   fLongLegId  =  gMC->Gsvolu(name.Data(),"TUBE",(*fIdtmed)[kPlasticId],par,3);
343
344   fInner->SetupGeometry((*fIdtmed)[kAirId], 
345                         (*fIdtmed)[kSiId], 
346                         (*fIdtmed)[kPcbId], 
347                         fPrintboardRotationId, 
348                         fIdentityRotationId);
349   fOuter->SetupGeometry((*fIdtmed)[kAirId], 
350                         (*fIdtmed)[kSiId], 
351                         (*fIdtmed)[kPcbId], 
352                         fPrintboardRotationId, 
353                         fIdentityRotationId);
354
355   fFMD1->SetupGeometry((*fIdtmed)[kAirId], (*fIdtmed)[kKaptionId]);
356   fFMD2->SetupGeometry((*fIdtmed)[kAirId], (*fIdtmed)[kKaptionId]);
357   fFMD3->SetupGeometry((*fIdtmed)[kAirId], (*fIdtmed)[kKaptionId]);
358   
359   fFMD1->Geometry("ALIC", fPrintboardRotationId, fIdentityRotationId);
360   fFMD2->Geometry("ALIC", fPrintboardRotationId, fIdentityRotationId);
361   fFMD3->Geometry("ALIC", fPrintboardRotationId, fIdentityRotationId);    
362 }    
363
364 //____________________________________________________________________
365 void AliFMD::CreateMaterials() 
366 {
367   // Register various materials and tracking mediums with the
368   // backend.   
369   // 
370   // Currently defined materials and mediums are 
371   // 
372   //    FMD Air         Normal air 
373   //    FMD Si          Active silicon of sensors 
374   //    FMD Carbon      Normal carbon used in support, etc. 
375   //    FMD Kapton      Carbon used in Honeycomb
376   //    FMD PCB         Printed circuit board material 
377   //    FMD Plastic     Material for support legs 
378   // 
379   // Also defined are two rotation matricies. 
380   //
381   // DebugGuard guard("AliFMD::CreateMaterials");
382   AliDebug(10, "Creating materials");
383   Int_t    id;
384   Double_t a                = 0;
385   Double_t z                = 0;
386   Double_t density          = 0;
387   Double_t radiationLength  = 0;
388   Double_t absorbtionLength = 999;
389   Int_t    fieldType        = gAlice->Field()->Integ();     // Field type 
390   Double_t maxField         = gAlice->Field()->Max();     // Field max.
391   Double_t maxBending       = 0;     // Max Angle
392   Double_t maxStepSize      = 0.001; // Max step size 
393   Double_t maxEnergyLoss    = 1;     // Max Delta E
394   Double_t precision        = 0.001; // Precision
395   Double_t minStepSize      = 0.001; // Minimum step size 
396  
397   // Silicon 
398   a                = 28.0855;
399   z                = 14.;
400   density          = fSiDensity;
401   radiationLength  = 9.36;
402   maxBending       = 1;
403   maxStepSize      = .001;
404   precision        = .001;
405   minStepSize      = .001;
406   id               = kSiId;
407   AliMaterial(id, "FMD Si$", a, z, density, radiationLength, absorbtionLength);
408   AliMedium(kSiId, "FMD Si$",id,1,fieldType,maxField,maxBending,
409             maxStepSize,maxEnergyLoss,precision,minStepSize);
410
411
412   // Carbon 
413   a                = 12.011;
414   z                = 6.;
415   density          = 2.265;
416   radiationLength  = 18.8;
417   maxBending       = 10;
418   maxStepSize      = .01;
419   precision        = .003;
420   minStepSize      = .003;
421   id               = kCarbonId;
422   AliMaterial(id, "FMD Carbon$", a, z, density, radiationLength, 
423               absorbtionLength);
424   AliMedium(kCarbonId, "FMD Carbon$",id,0,fieldType,maxField,maxBending,
425             maxStepSize,maxEnergyLoss,precision,minStepSize);
426
427   // Silicon chip 
428   {
429     Float_t as[] = { 12.0107,      14.0067,      15.9994,
430                      1.00794,      28.0855,     107.8682 };
431     Float_t zs[] = {  6.,           7.,           8.,
432                       1.,          14.,          47. };
433     Float_t ws[] = {  0.039730642,  0.001396798,  0.01169634,
434                       0.004367771,  0.844665,     0.09814344903 };
435     density = 2.36436;
436     maxBending       = 10;
437     maxStepSize      = .01;
438     precision        = .003;
439     minStepSize      = .003;
440     id = kSiChipId;
441     AliMixture(id, "FMD Si Chip$", as, zs, density, 6, ws);
442     AliMedium(kSiChipId, "FMD Si Chip$", id, 0, fieldType, maxField, 
443               maxBending, maxStepSize, maxEnergyLoss, precision, minStepSize);
444   }
445   
446
447   // Kaption 
448   {
449     Float_t as[] = { 1.00794,  12.0107,  14.010,   15.9994};
450     Float_t zs[] = { 1.,        6.,       7.,       8.};
451     Float_t ws[] = { 0.026362,  0.69113,  0.07327,  0.209235};
452     density          = 1.42;
453     maxBending       = 1;
454     maxStepSize      = .001;
455     precision        = .001;
456     minStepSize      = .001;
457     id               = kKaptionId;
458     AliMixture(id, "FMD Kaption$", as, zs, density, 4, ws);
459     AliMedium(kKaptionId, "FMD Kaption$",id,0,fieldType,maxField,maxBending,
460               maxStepSize,maxEnergyLoss,precision,minStepSize);
461   }
462   
463   // Air
464   {
465     Float_t as[] = { 12.0107, 14.0067,   15.9994,  39.948 };
466     Float_t zs[] = {  6.,      7.,       8.,       18. };
467     Float_t ws[] = { 0.000124, 0.755267, 0.231781, 0.012827 }; 
468     density      = .00120479;
469     maxBending   = 1;
470     maxStepSize  = .001;
471     precision    = .001;
472     minStepSize  = .001;
473     id           = kAirId;
474     AliMixture(id, "FMD Air$", as, zs, density, 4, ws);
475     AliMedium(kAirId, "FMD Air$", id,0,fieldType,maxField,maxBending,
476               maxStepSize,maxEnergyLoss,precision,minStepSize);
477   }
478   
479   // PCB
480   {
481     Float_t zs[] = { 14.,         20.,         13.,         12.,
482                       5.,         22.,         11.,         19.,
483                      26.,          9.,          8.,          6.,
484                       7.,          1.};
485     Float_t as[] = { 28.0855,     40.078,      26.981538,   24.305, 
486                      10.811,      47.867,      22.98977,    39.0983,
487                      55.845,      18.9984,     15.9994,     12.0107,
488                      14.0067,      1.00794};
489     Float_t ws[] = {  0.15144894,  0.08147477,  0.04128158,  0.00904554, 
490                       0.01397570,  0.00287685,  0.00445114,  0.00498089,
491                       0.00209828,  0.00420000,  0.36043788,  0.27529426,
492                       0.01415852,  0.03427566};
493     density      = 1.8;
494     maxBending   = 1;
495     maxStepSize  = .001;
496     precision    = .001;
497     minStepSize  = .001;
498     id           = kPcbId;
499     AliMixture(id, "FMD PCB$", as, zs, density, 14, ws);
500     AliMedium(kPcbId, "FMD PCB$", id,1,fieldType,maxField,maxBending,
501               maxStepSize,maxEnergyLoss,precision,minStepSize);
502   }
503   
504   // Plastic 
505   {
506     Float_t as[] = { 1.01, 12.01 };
507     Float_t zs[] = { 1.,   6.    };
508     Float_t ws[] = { 1.,   1.    };
509     density      = 1.03;
510     maxBending   = 10;
511     maxStepSize  = .01;
512     precision    = .003;
513     minStepSize  = .003;
514     id           = kPlasticId;
515     AliMixture(id, "FMD Plastic$", as, zs, density, -2, ws);
516     AliMedium(kPlasticId, "FMD Plastic$", id,0,fieldType,maxField,maxBending,
517                 maxStepSize,maxEnergyLoss,precision,minStepSize);
518   }
519   AliMatrix(fPrintboardRotationId, 90, 90, 0, 90, 90, 0);
520   AliMatrix(fIdentityRotationId, 90, 0, 90, 90, 0, 0);
521 }
522
523 //____________________________________________________________________
524 void  
525 AliFMD::Init()
526 {
527   //
528   // Initialis the FMD after it has been built
529   Int_t i;
530   //
531   if (fDebug) {
532     std::cout << "\n" << ClassName() << ": " << std::flush;
533     for (i = 0; i < 35; i++) std::cout << "*";
534     std::cout << " FMD_INIT ";
535     for (i = 0; i < 35; i++) std::cout << "*";
536     std::cout << "\n" << ClassName() << ": " << std::flush;
537     //
538     // Here the FMD initialisation code (if any!)
539     for (i = 0; i < 80; i++) std::cout << "*";
540     std::cout << std::endl;
541   }
542   //
543   //
544 }
545
546 //====================================================================
547 //
548 // Graphics and event display
549 //
550 //____________________________________________________________________
551 void 
552 AliFMD::BuildGeometry()
553 {
554   //
555   // Build simple ROOT TNode geometry for event display
556   //
557   // Build a simplified geometry of the FMD used for event display  
558   // 
559   // The actual building of the TNodes is done by
560   // AliFMDSubDetector::SimpleGeometry. 
561   AliDebug(10, "Creating a simplified geometry");
562
563   TNode* top = gAlice->GetGeometry()->GetNode("alice");
564   
565   fFMD1->SimpleGeometry(fNodes, top, GetLineColor(), 0);
566   fFMD2->SimpleGeometry(fNodes, top, GetLineColor(), 0);
567   fFMD3->SimpleGeometry(fNodes, top, GetLineColor(), 0);
568 }
569
570 //____________________________________________________________________
571 void 
572 AliFMD::DrawDetector()
573 {
574   //
575   // Draw a shaded view of the Forward multiplicity detector
576   //
577   // DebugGuard guard("AliFMD::DrawDetector");
578   AliDebug(10, "Draw detector");
579   
580   //Set ALIC mother transparent
581   gMC->Gsatt("ALIC","SEEN",0);
582
583   //Set volumes visible
584   fFMD1->Gsatt();
585   fFMD2->Gsatt();
586   fFMD3->Gsatt();
587   fInner->Gsatt();
588   fOuter->Gsatt();
589
590   //
591   gMC->Gdopt("hide", "on");
592   gMC->Gdopt("shad", "on");
593   gMC->Gsatt("*", "fill", 7);
594   gMC->SetClipBox(".");
595   gMC->SetClipBox("*", 0, 1000, -1000, 1000, -1000, 1000);
596   gMC->DefaultRange();
597   gMC->Gdraw("alic", 40, 30, 0, 12, 12, .055, .055);
598   gMC->Gdhead(1111, "Forward Multiplicity Detector");
599   gMC->Gdman(16, 10, "MAN");
600   gMC->Gdopt("hide", "off");
601 }
602
603 //____________________________________________________________________
604 const Int_t 
605 AliFMD::DistanceToPrimitive(Int_t, Int_t)
606 {
607   //
608   // Calculate the distance from the mouse to the FMD on the screen
609   // Dummy routine
610   //
611   return 9999;
612 }
613
614 //====================================================================
615 //
616 // Hit and Digit managment 
617 //
618 //____________________________________________________________________
619 void 
620 AliFMD::MakeBranch(Option_t * option)
621 {
622   // Create Tree branches for the FMD.
623   //
624   // Options:
625   //
626   //    H          Make a branch of TClonesArray of AliFMDHit's
627   //    D          Make a branch of TClonesArray of AliFMDDigit's
628   //    S          Make a branch of TClonesArray of AliFMDSDigit's
629   // 
630   const Int_t kBufferSize = 16000;
631   TString branchname(GetName());
632   TString opt(option);
633   
634   if (opt.Contains("H", TString::kIgnoreCase)) {
635     HitsArray();
636     AliDetector::MakeBranch(option); 
637   }
638   if (opt.Contains("D", TString::kIgnoreCase)) { 
639     DigitsArray();
640     MakeBranchInTree(fLoader->TreeD(), branchname.Data(),
641                      &fDigits, kBufferSize, 0);
642   }
643   if (opt.Contains("S", TString::kIgnoreCase)) { 
644     SDigitsArray();
645     MakeBranchInTree(fLoader->TreeS(), branchname.Data(),
646                      &fSDigits, kBufferSize, 0);
647   }
648 }
649
650 //____________________________________________________________________
651 void 
652 AliFMD::SetTreeAddress()
653 {
654   // Set branch address for the Hits and Digits Tree.
655
656   if (fLoader->TreeH()) HitsArray();
657   AliDetector::SetTreeAddress();
658
659   TTree *treeD = fLoader->TreeD();
660   if (treeD) {
661     DigitsArray();
662     TBranch* branch = treeD->GetBranch ("FMD");
663     if (branch) branch->SetAddress(&fDigits);
664   }
665
666   TTree *treeS = fLoader->TreeS();
667   if (treeS) {
668     SDigitsArray();
669     TBranch* branch = treeS->GetBranch ("FMD");
670     if (branch) branch->SetAddress(&fSDigits);
671   }
672 }
673
674
675
676 //____________________________________________________________________
677 void 
678 AliFMD::SetHitsAddressBranch(TBranch *b)
679 {
680   // Set the TClonesArray to read hits into. 
681   b->SetAddress(&fHits);
682 }
683
684 //____________________________________________________________________
685 void 
686 AliFMD::AddHit(Int_t track, Int_t *vol, Float_t *hits) 
687 {
688   // Add a hit to the hits tree 
689   // 
690   // The information of the two arrays are decoded as 
691   // 
692   // Parameters
693   //    track                Track #
694   //    ivol[0]  [UShort_t ] Detector # 
695   //    ivol[1]  [Char_t   ] Ring ID 
696   //    ivol[2]  [UShort_t ] Sector #
697   //    ivol[3]  [UShort_t ] Strip # 
698   //    hits[0]  [Float_t  ] Track's X-coordinate at hit 
699   //    hits[1]  [Float_t  ] Track's Y-coordinate at hit
700   //    hits[3]  [Float_t  ] Track's Z-coordinate at hit
701   //    hits[4]  [Float_t  ] X-component of track's momentum             
702   //    hits[5]  [Float_t  ] Y-component of track's momentum             
703   //    hits[6]  [Float_t  ] Z-component of track's momentum            
704   //    hits[7]  [Float_t  ] Energy deposited by track                  
705   //    hits[8]  [Int_t    ] Track's particle Id # 
706   //    hits[9]  [Float_t  ] Time when the track hit
707   // 
708   // 
709   AddHit(track, 
710          UShort_t(vol[0]),  // Detector # 
711          Char_t(vol[1]),    // Ring ID
712          UShort_t(vol[2]),  // Sector # 
713          UShort_t(vol[3]),  // Strip # 
714          hits[0],           // X
715          hits[1],           // Y
716          hits[2],           // Z
717          hits[3],           // Px
718          hits[4],           // Py
719          hits[5],           // Pz
720          hits[6],           // Energy loss 
721          Int_t(hits[7]),    // PDG 
722          hits[8]);          // Time
723 }
724
725 //____________________________________________________________________
726 void 
727 AliFMD::AddHit(Int_t    track, 
728                UShort_t detector, 
729                Char_t   ring, 
730                UShort_t sector, 
731                UShort_t strip, 
732                Float_t  x, 
733                Float_t  y, 
734                Float_t  z,
735                Float_t  px, 
736                Float_t  py, 
737                Float_t  pz,
738                Float_t  edep,
739                Int_t    pdg,
740                Float_t  t)
741 {
742   //
743   // Add a hit to the list
744   //
745   // Parameters:
746   // 
747   //    track     Track #
748   //    detector  Detector # (1, 2, or 3)                      
749   //    ring      Ring ID ('I' or 'O')
750   //    sector    Sector # (For inner/outer rings: 0-19/0-39)
751   //    strip     Strip # (For inner/outer rings: 0-511/0-255)
752   //    x         Track's X-coordinate at hit
753   //    y         Track's Y-coordinate at hit
754   //    z         Track's Z-coordinate at hit
755   //    px        X-component of track's momentum 
756   //    py        Y-component of track's momentum
757   //    pz        Z-component of track's momentum
758   //    edep      Energy deposited by track
759   //    pdg       Track's particle Id #
760   //    t         Time when the track hit 
761   // 
762   TClonesArray& a = *(HitsArray());
763   // Search through the list of already registered hits, and see if we
764   // find a hit with the same parameters.  If we do, then don't create
765   // a new hit, but rather update the energy deposited in the hit.
766   // This is done, so that a FLUKA based simulation will get the
767   // number of hits right, not just the enerrgy deposition. 
768   for (Int_t i = 0; i < fNhits; i++) {
769     if (!a.At(i)) continue;
770     AliFMDHit* hit = static_cast<AliFMDHit*>(a.At(i));
771     if (hit->Detector() == detector 
772         && hit->Ring() == ring
773         && hit->Sector() == sector 
774         && hit->Strip() == strip
775         && hit->Track() == track) {
776       Warning("AddHit", "already had a hit in FMD%d%c[%2d,%3d] for track # %d,"
777               " adding energy (%f) to that hit (%f) -> %f", 
778               detector, ring, sector, strip, track, edep, hit->Edep(),
779               hit->Edep() + edep);
780       hit->SetEdep(hit->Edep() + edep);
781       return;
782     }
783   }
784   // If hit wasn't already registered, do so know. 
785   new (a[fNhits]) AliFMDHit(fIshunt, track, detector, ring, sector, strip, 
786                             x, y, z, px, py, pz, edep, pdg, t);
787   fNhits++;
788 }
789
790 //____________________________________________________________________
791 void 
792 AliFMD::AddDigit(Int_t* digits)
793 {
794   // Add a digit to the Digit tree 
795   // 
796   // Paramters 
797   //
798   //    digits[0]  [UShort_t] Detector #
799   //    digits[1]  [Char_t]   Ring ID
800   //    digits[2]  [UShort_t] Sector #
801   //    digits[3]  [UShort_t] Strip #
802   //    digits[4]  [UShort_t] ADC Count 
803   //    digits[5]  [Short_t]  ADC Count, -1 if not used
804   //    digits[6]  [Short_t]  ADC Count, -1 if not used 
805   // 
806   AddDigit(UShort_t(digits[0]),  // Detector #
807            Char_t(digits[1]),    // Ring ID
808            UShort_t(digits[2]),  // Sector #
809            UShort_t(digits[3]),  // Strip #
810            UShort_t(digits[4]),  // ADC Count1 
811            Short_t(digits[5]),   // ADC Count2 
812            Short_t(digits[6]));  // ADC Count3 
813 }
814
815 //____________________________________________________________________
816 void 
817 AliFMD::AddDigit(UShort_t detector, 
818                  Char_t   ring, 
819                  UShort_t sector, 
820                  UShort_t strip, 
821                  UShort_t count1, 
822                  Short_t  count2,
823                  Short_t  count3)
824 {
825   // add a real digit - as coming from data
826   // 
827   // Parameters 
828   //
829   //    detector  Detector # (1, 2, or 3)                      
830   //    ring      Ring ID ('I' or 'O')
831   //    sector    Sector # (For inner/outer rings: 0-19/0-39)
832   //    strip     Strip # (For inner/outer rings: 0-511/0-255)
833   //    count1    ADC count (a 10-bit word)
834   //    count2    ADC count (a 10-bit word), or -1 if not used
835   //    count3    ADC count (a 10-bit word), or -1 if not used
836   TClonesArray& a = *(DigitsArray());
837   
838   new (a[fNdigits++]) 
839     AliFMDDigit(detector, ring, sector, strip, count1, count2, count3);
840 }
841
842 //____________________________________________________________________
843 void 
844 AliFMD::AddSDigit(Int_t* digits)
845 {
846   // Add a digit to the SDigit tree 
847   // 
848   // Paramters 
849   //
850   //    digits[0]  [UShort_t] Detector #
851   //    digits[1]  [Char_t]   Ring ID
852   //    digits[2]  [UShort_t] Sector #
853   //    digits[3]  [UShort_t] Strip #
854   //    digits[4]  [Float_t]  Total energy deposited 
855   //    digits[5]  [UShort_t] ADC Count 
856   //    digits[6]  [Short_t]  ADC Count, -1 if not used
857   //    digits[7]  [Short_t]  ADC Count, -1 if not used 
858   // 
859   AddSDigit(UShort_t(digits[0]),  // Detector #
860             Char_t(digits[1]),    // Ring ID
861             UShort_t(digits[2]),  // Sector #
862             UShort_t(digits[3]),  // Strip #
863             Float_t(digits[4]),   // Edep
864             UShort_t(digits[5]),  // ADC Count1 
865             Short_t(digits[6]),   // ADC Count2 
866             Short_t(digits[7]));  // ADC Count3 
867 }
868
869 //____________________________________________________________________
870 void 
871 AliFMD::AddSDigit(UShort_t detector, 
872                   Char_t   ring, 
873                   UShort_t sector, 
874                   UShort_t strip, 
875                   Float_t  edep,
876                   UShort_t count1, 
877                   Short_t  count2,
878                   Short_t  count3)
879 {
880   // add a summable digit
881   // 
882   // Parameters 
883   //
884   //    detector  Detector # (1, 2, or 3)                      
885   //    ring      Ring ID ('I' or 'O')
886   //    sector    Sector # (For inner/outer rings: 0-19/0-39)
887   //    strip     Strip # (For inner/outer rings: 0-511/0-255)
888   //    edep      Total energy deposited
889   //    count1    ADC count (a 10-bit word)
890   //    count2    ADC count (a 10-bit word), or -1 if not used
891   //    count3    ADC count (a 10-bit word), or -1 if not used
892   //
893   TClonesArray& a = *(SDigitsArray());
894   
895   new (a[fNsdigits++]) 
896     AliFMDSDigit(detector, ring, sector, strip, edep, count1, count2, count3);
897 }
898
899 //____________________________________________________________________
900 void 
901 AliFMD::ResetSDigits()
902 {
903   //
904   // Reset number of digits and the digits array for this detector
905   //
906   fNsdigits   = 0;
907   if (fSDigits) fSDigits->Clear();
908 }
909
910
911 //____________________________________________________________________
912 TClonesArray*
913 AliFMD::HitsArray() 
914 {
915   // Initialize hit array if not already, and return pointer to it. 
916   if (!fHits) { 
917     fHits = new TClonesArray("AliFMDHit", 1000);
918     fNhits = 0;
919   }
920   return fHits;
921 }
922
923 //____________________________________________________________________
924 TClonesArray*
925 AliFMD::DigitsArray() 
926 {
927   // Initialize digit array if not already, and return pointer to it. 
928   if (!fDigits) { 
929     fDigits = new TClonesArray("AliFMDDigit", 1000);
930     fNdigits = 0;
931   }
932   return fDigits;
933 }
934
935 //____________________________________________________________________
936 TClonesArray*
937 AliFMD::SDigitsArray() 
938 {
939   // Initialize digit array if not already, and return pointer to it. 
940   if (!fSDigits) { 
941     fSDigits = new TClonesArray("AliFMDSDigit", 1000);
942     fNsdigits = 0;
943   }
944   return fSDigits;
945 }
946
947 //====================================================================
948 //
949 // Digitization 
950 //
951 //____________________________________________________________________
952 void 
953 AliFMD::Hits2Digits() 
954 {
955   // Create AliFMDDigit's from AliFMDHit's.  This is done by making a
956   // AliFMDDigitizer, and executing that code.
957   // 
958   AliRunDigitizer* manager = new AliRunDigitizer(1, 1);
959   manager->SetInputStream(0, "galice.root");
960   manager->SetOutputFile("H2Dfile");
961   
962   /* AliDigitizer* dig =*/ CreateDigitizer(manager);
963   manager->Exec("");
964 }
965
966 //____________________________________________________________________
967 void 
968 AliFMD::Hits2SDigits() 
969 {
970   // Create AliFMDSDigit's from AliFMDHit's.  This is done by creating
971   // an AliFMDSDigitizer object, and executing it. 
972   // 
973   AliDigitizer* sdig = new AliFMDSDigitizer("galice.root");
974   sdig->Exec("");
975 }
976
977   
978 //____________________________________________________________________
979 AliDigitizer* 
980 AliFMD::CreateDigitizer(AliRunDigitizer* manager) const
981 {
982   // Create a digitizer object 
983   return new AliFMDDigitizer(manager);
984 }
985
986 //====================================================================
987 //
988 // Raw data simulation 
989 //
990 //__________________________________________________________________
991 void 
992 AliFMD::Digits2Raw() 
993 {
994   // Turn digits into raw data. 
995   // 
996   // Digits are read from the Digit branch, and processed to make
997   // three DDL files, one for each of the sub-detectors FMD1, FMD2,
998   // and FMD3. 
999   //
1000   // The raw data files consists of a header, followed by ALTRO
1001   // formatted blocks.  
1002   // 
1003   //          +-------------+
1004   //          | Header      |
1005   //          +-------------+
1006   //          | ALTRO Block |
1007   //          | ...         |
1008   //          +-------------+
1009   //          DDL file 
1010   // 
1011   // An ALTRO formatted block, in the FMD context, consists of a
1012   // number of counts followed by a trailer. 
1013   // 
1014   //          +------------------+
1015   //          | Count            |
1016   //          | ...              |
1017   //          | possible fillers |
1018   //          +------------------+
1019   //          | Trailer          |
1020   //          +------------------+
1021   //          ALTRO block 
1022   // 
1023   // The counts are listed backwards, that is, starting with the
1024   // latest count, and ending in the first. 
1025   // 
1026   // Each count consist of 1 or more ADC samples of the VA1_ALICE
1027   // pre-amp. signal.  Just how many samples are used depends on
1028   // whether the ALTRO over samples the pre-amp.  Each sample is a
1029   // 10-bit word, and the samples are grouped into 40-bit blocks 
1030   //
1031   //          +------------------------------------+
1032   //          |  S(n)   | S(n-1) | S(n-2) | S(n-3) |
1033   //          |  ...    | ...    | ...    | ...    |
1034   //          |  S(2)   | S(1)   | AA     | AA     |
1035   //          +------------------------------------+
1036   //          Counts + possible filler 
1037   //
1038   // The trailer of the number of words of signales, the starting
1039   // strip number, the sector number, and the ring ID; each 10-bit
1040   // words,  packed into 40-bits. 
1041   // 
1042   //          +------------------------------------+
1043   //          | # words | start  | sector | ring   |
1044   //          +------------------------------------+
1045   //          Trailer
1046   // 
1047   // Note, that this method assumes that the digits are ordered. 
1048   //
1049   AliFMD* fmd = static_cast<AliFMD*>(gAlice->GetDetector(GetName()));
1050   fLoader->LoadDigits();
1051   TTree* digitTree = fLoader->TreeD();
1052   if (!digitTree) {
1053     Error("Digits2Raw", "no digit tree");
1054     return;
1055   }
1056   
1057   TClonesArray* digits = new TClonesArray("AliFMDDigit", 1000);
1058   fmd->SetTreeAddress();
1059   TBranch* digitBranch = digitTree->GetBranch(GetName());
1060   if (!digitBranch) {
1061     Error("Digits2Raw", "no branch for %s", GetName());
1062     return;
1063   }
1064   digitBranch->SetAddress(&digits);
1065   
1066   Int_t nEvents = Int_t(digitTree->GetEntries());
1067   for (Int_t event = 0; event < nEvents; event++) {
1068     fmd->ResetDigits();
1069     digitTree->GetEvent(event);
1070     
1071     Int_t nDigits = digits->GetEntries();
1072     if (nDigits < 1) continue;
1073
1074
1075     UShort_t prevDetector = 0;
1076     Char_t   prevRing     = '\0';
1077     UShort_t prevSector   = 0;
1078     // UShort_t prevStrip    = 0;
1079
1080     // The first seen strip number for a channel 
1081     UShort_t startStrip   = 0;
1082     
1083     // Which channel number in the ALTRO channel we're at 
1084     UShort_t offset       = 0;
1085
1086     // How many times the ALTRO Samples one VA1_ALICE channel 
1087     Int_t sampleRate = 1;
1088
1089     // A buffer to hold 1 ALTRO channel - Normally, one ALTRO channel
1090     // holds 128 VA1_ALICE channels, sampled at a rate of `sampleRate' 
1091     TArrayI channel(128 * sampleRate);
1092     
1093     // The Altro buffer 
1094     AliAltroBuffer* altro = 0;
1095     
1096     // Loop over the digits in the event.  Note, that we assume the
1097     // the digits are in order in the branch.   If they were not, we'd
1098     // have to cache all channels before we could write the data to
1099     // the ALTRO buffer, or we'd have to set up a map of the digits. 
1100     for (Int_t i = 0; i < nDigits; i++) {
1101       // Get the digit
1102       AliFMDDigit* digit = static_cast<AliFMDDigit*>(digits->At(i));
1103
1104       UShort_t det    = digit->Detector();
1105       Char_t   ring   = digit->Ring();
1106       UShort_t sector = digit->Sector();
1107       UShort_t strip  = digit->Strip();
1108       if (det != prevDetector) {
1109         AliDebug(10, Form("FMD: New DDL, was %d, now %d",
1110                           kBaseDDL + prevDetector - 1,
1111                           kBaseDDL + det - 1));
1112         // If an altro exists, delete the object, flushing the data to
1113         // disk, and closing the file. 
1114         if (altro) { 
1115           // When the first argument is false, we write the real
1116           // header. 
1117           AliDebug(10, Form("New altro: Write channel at %d Strip: %d "
1118                             "Sector: %d  Ring: %d", 
1119                             i, startStrip, prevSector, prevRing));
1120           // TPC to FMD translations 
1121           // 
1122           //    TPC                FMD
1123           //    ----------+-----------
1124           //    pad       |      strip
1125           //    row       |     sector
1126           //    sector    |       ring
1127           // 
1128           altro->WriteChannel(Int_t(startStrip), 
1129                               Int_t(prevSector), 
1130                               Int_t((prevRing == 'I' ? 0 : 1)), 
1131                               channel.fN, channel.fArray, 0);
1132           altro->Flush();
1133           altro->WriteDataHeader(kFALSE, kFALSE);
1134           delete altro;
1135           altro = 0;
1136         }
1137
1138         prevDetector = det;
1139         // Need to open a new DDL! 
1140         Int_t ddlId = kBaseDDL + det - 1;
1141         TString filename(Form("%s_%d.ddl", GetName(),  ddlId));
1142
1143         AliDebug(10, Form("New altro buffer with DDL file %s", 
1144                           filename.Data()));
1145         AliDebug(10, Form("New altro at %d", i));
1146         // Create a new altro buffer - a `1' as the second argument
1147         // means `write mode' 
1148         altro = new AliAltroBuffer(filename.Data(), 1);
1149         
1150         // Write a dummy (first argument is true) header to the DDL
1151         // file - later on, when we close the file, we write the real
1152         // header
1153         altro->WriteDataHeader(kTRUE, kFALSE);
1154
1155         // Figure out the sample rate 
1156         if (digit->Count2() > 0) sampleRate = 2;
1157         if (digit->Count3() > 0) sampleRate = 3;
1158
1159         channel.Set(128 * sampleRate);
1160         offset     = 0;
1161         prevRing   = ring;
1162         prevSector = sector;
1163         startStrip = strip;
1164       }
1165       else if (offset == 128                        
1166                || digit->Ring() != prevRing 
1167                || digit->Sector() != prevSector) {
1168         // Force a new Altro channel
1169         AliDebug(10, Form("Flushing channel to disk because %s",
1170                           (offset == 128 ? "channel is full" :
1171                            (ring != prevRing ? "new ring up" :
1172                             "new sector up"))));
1173         AliDebug(10, Form("New Channel: Write channel at %d Strip: %d "
1174                           "Sector: %d  Ring: %d", 
1175                           i, startStrip, prevSector, prevRing));
1176         altro->WriteChannel(Int_t(startStrip), 
1177                             Int_t(prevSector), 
1178                             Int_t((prevRing == 'I' ? 0 : 1)), 
1179                             channel.fN, channel.fArray, 0);
1180         // Reset and update channel variables 
1181         channel.Reset(0);
1182         offset     = 0; 
1183         startStrip = strip;
1184         prevRing   = ring;
1185         prevSector = sector;
1186       }
1187
1188       // Store the counts of the ADC in the channel buffer 
1189       channel[offset * sampleRate] = digit->Count1();
1190       if (sampleRate > 1) 
1191         channel[offset * sampleRate + 1] = digit->Count2();
1192       if (sampleRate > 2) 
1193         channel[offset * sampleRate + 2] = digit->Count3();
1194       offset++;
1195     }
1196     // Finally, we need to close the final ALTRO buffer if it wasn't
1197     // already 
1198     if (altro) {
1199       altro->Flush();
1200       altro->WriteDataHeader(kFALSE, kFALSE);
1201       delete altro;
1202     }
1203   }
1204   fLoader->UnloadDigits();
1205 }
1206
1207 //==================================================================
1208 //
1209 // Various setter functions for the common paramters 
1210 //
1211
1212 //__________________________________________________________________
1213 void 
1214 AliFMD::SetLegLength(Double_t length) 
1215 {
1216   // Set lenght of plastic legs that hold the hybrid (print board and
1217   // silicon sensor) onto the honeycomp support
1218   //
1219   // DebugGuard guard("AliFMD::SetLegLength");
1220   AliDebug(10, "AliFMD::SetLegLength");
1221   fLegLength = length;
1222   fInner->SetLegLength(fLegLength);
1223   fOuter->SetLegLength(fLegLength);
1224 }
1225
1226 //__________________________________________________________________
1227 void 
1228 AliFMD::SetLegOffset(Double_t offset) 
1229 {
1230   // Set offset from edge of hybrid to plastic legs that hold the
1231   // hybrid (print board and silicon sensor) onto the honeycomp
1232   // support 
1233   //
1234   // DebugGuard guard("AliFMD::SetLegOffset");
1235   AliDebug(10, "AliFMD::SetLegOffset");
1236   fInner->SetLegOffset(offset);
1237   fOuter->SetLegOffset(offset);
1238 }
1239
1240 //__________________________________________________________________
1241 void 
1242 AliFMD::SetLegRadius(Double_t radius) 
1243 {
1244   // Set the diameter of the plastic legs that hold the hybrid (print
1245   // board and silicon sensor) onto the honeycomp support
1246   //
1247   // DebugGuard guard("AliFMD::SetLegRadius");
1248   AliDebug(10, "AliFMD::SetLegRadius");
1249   fLegRadius = radius;
1250   fInner->SetLegRadius(fLegRadius);
1251   fOuter->SetLegRadius(fLegRadius);
1252 }
1253
1254 //__________________________________________________________________
1255 void 
1256 AliFMD::SetModuleSpacing(Double_t spacing) 
1257 {
1258   // Set the distance between the front and back sensor modules
1259   // (module staggering). 
1260   //
1261   // DebugGuard guard("AliFMD::SetModuleSpacing");
1262   AliDebug(10, "AliFMD::SetModuleSpacing");  
1263   fModuleSpacing = spacing;
1264   fInner->SetModuleSpacing(fModuleSpacing);
1265   fOuter->SetModuleSpacing(fModuleSpacing);
1266 }
1267
1268 //====================================================================
1269 //
1270 // Utility 
1271 //
1272 //__________________________________________________________________
1273 void 
1274 AliFMD::Browse(TBrowser* b) 
1275 {
1276   // Browse this object. 
1277   //
1278   AliDebug(10, "AliFMD::Browse");
1279   AliDetector::Browse(b);
1280   if (fInner) b->Add(fInner, "Inner Ring");
1281   if (fOuter) b->Add(fOuter, "Outer Ring");
1282   if (fFMD1)  b->Add(fFMD1,  "FMD1 SubDetector");
1283   if (fFMD2)  b->Add(fFMD2,  "FMD2 SubDetector");
1284   if (fFMD3)  b->Add(fFMD3,  "FMD3 SubDetector");
1285 }
1286
1287
1288 //___________________________________________________________________
1289 //
1290 // EOF
1291 //