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 **************************************************************************/
18 //____________________________________________________________________
20 // Forward Multiplicity Detector based on Silicon wafers. This class
21 // contains the base procedures for the Forward Multiplicity detector
22 // Detector consists of 3 sub-detectors FMD1, FMD2, and FMD3, each of
23 // which has 1 or 2 rings of silicon sensors.
25 // This is the base class for all FMD manager classes.
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 simulation
31 // +--------+ 1 +-----------------+
32 // | AliFMD |<>-----| AliFMDSimulator |
33 // +--------+ +-----------------+
36 // +-------------+-------------+
38 // +--------------------+ +-------------------+
39 // | AliFMDGeoSimulator | | AliFMDG3Simulator |
40 // +--------------------+ +-------------------+
43 // +--------------------+
44 // | AliFMDOldSimulator |
45 // +--------------------+
48 // This defines the interface for the various parts of AliROOT that
49 // uses the FMD, like AliFMDSimulator, AliFMDDigitizer,
50 // AliFMDReconstructor, and so on.
53 // This is the base class for the FMD simulation tasks. The
54 // simulator tasks are responsible to implment the geoemtry, and
57 // * AliFMDGeoSimulator
58 // This is a concrete implementation of the AliFMDSimulator that
59 // uses the TGeo classes directly only. This defines the active
60 // volume as an ONLY XTRU shape with a divided MANY TUBS shape
61 // inside to implement the particular shape of the silicon
64 // * AliFMDG3Simulator
65 // This is a concrete implementation of the AliFMDSimulator that
66 // uses the TVirtualMC interface with GEANT 3.21-like messages.
67 // This implements the active volume as a divided TUBS shape. Hits
68 // in the corners should be cut away at run time (but currently
71 // * AliFMDOldSimulator
72 // This is a concrete implementation of AliFMDSimulator. It
73 // approximates the of the rings as segmented disks.
76 #include "AliFMDG3Simulator.h" // ALIFMDG3SIMULATOR_H
77 #include "AliFMDGeometry.h" // ALIFMDGEOMETRY_H
78 #include "AliFMDDetector.h" // ALIFMDDETECTOR_H
79 #include "AliFMDRing.h" // ALIFMDRING_H
80 #include "AliFMD1.h" // ALIFMD1_H
81 #include "AliFMD2.h" // ALIFMD2_H
82 #include "AliFMD3.h" // ALIFMD3_H
83 #include "AliFMD.h" // ALIFMD_H
84 #include <AliLog.h> // ALILOG_H
85 #include <TVector2.h> // ROOT_TVector2
86 #include <TVirtualMC.h> // ROOT_TVirtualMC
87 #include <TArrayI.h> // ROOT_TArrayI
89 //====================================================================
90 ClassImp(AliFMDG3Simulator)
92 ; // This is here to keep Emacs for indenting the next line
95 //____________________________________________________________________
96 AliFMDG3Simulator::AliFMDG3Simulator()
98 // Default constructor
105 //____________________________________________________________________
106 AliFMDG3Simulator::AliFMDG3Simulator(AliFMD* fmd, Bool_t detailed)
107 : AliFMDSimulator(fmd, detailed)
109 // Normal constructor
113 // fmd Pointer to AliFMD object
114 // detailed Whether to make a detailed simulation or not
122 //____________________________________________________________________
124 AliFMDG3Simulator::RingGeometry(AliFMDRing* r)
126 // Setup the geometry of a ring. The defined TGeoVolume is
127 // returned, and should be used when setting up the rest of the
132 // r Pointer to ring geometry object
138 AliError("Didn't get a ring object");
141 Char_t id = r->GetId();
142 Double_t siThick = r->GetSiThickness();
143 // const Int_t nv = r->GetNVerticies();
144 TVector2* a = r->GetVertex(5);
145 TVector2* b = r->GetVertex(3);
146 TVector2* c = r->GetVertex(4);
147 Double_t theta = r->GetTheta();
148 Double_t off = (TMath::Tan(TMath::Pi() * theta / 180)
149 * r->GetBondingWidth());
150 Double_t rmax = b->Mod();
151 Double_t rmin = r->GetLowR();
152 Double_t pcbThick = r->GetPrintboardThickness();
153 Double_t modSpace = r->GetModuleSpacing();
154 Double_t legr = r->GetLegRadius();
155 Double_t legl = r->GetLegLength();
156 Double_t legoff = r->GetLegOffset();
157 Int_t ns = r->GetNStrips();
158 Double_t space = r->GetSpacing();
159 Double_t stripoff = a->Mod();
160 Double_t dstrip = (rmax - stripoff) / ns;
164 TVirtualMC* mc = TVirtualMC::GetMC();
166 Int_t siId = fFMD->GetIdtmed()->At(kSiId);
167 Int_t airId = fFMD->GetIdtmed()->At(kAirId);
168 Int_t pcbId = fFMD->GetIdtmed()->At(kPcbId);
169 Int_t plaId = fFMD->GetIdtmed()->At(kPlasticId);
170 // Int_t copId = fFMD->GetIdtmed()->At(kCopperId);
171 // Int_t chiId = fFMD->GetIdtmed()->At(kSiChipId);
173 Double_t ringWidth = r->GetRingDepth();
177 Double_t backWidth = siThick + pcbThick + legl + space;
178 Double_t frontWidth = backWidth + modSpace;
180 // Ring mother volume
183 par[2] = ringWidth / 2;
184 name = Form(fgkRingName, id);
185 mc->Gsvolu(name.Data(), "TUBE", airId, par, 3);
187 // Back container volume
190 par[2] = backWidth / 2;
193 TString backName(Form(fgkBackVName, id));
194 mc->Gsvolu(backName.Data(), "TUBS", airId, par, 5);
196 // Front container volume
197 par[2] = frontWidth / 2;
198 TString frontName(Form(fgkFrontVName, id));
199 mc->Gsvolu(frontName.Data(), "TUBS", airId, par, 5);
201 Double_t topL = (b->X() - c->X());
202 Double_t botL = (c->X() - a->X());
204 mc->Matrix(rot, 90, 90, 0, 90, 90, 0);
206 Double_t zFront = - frontWidth / 2 + siThick / 2;
207 Double_t zBack = - backWidth / 2 + siThick / 2;
214 // Virtual volume shape to divide - This volume is only defined if
215 // the geometry is set to be detailed.
218 par[2] = siThick / 2;
221 name = Form(fgkActiveName, id);
222 mc->Gsvolu(name.Data(), "TUBS", (fDetailed ? airId : siId), par, 5);
224 mc->Gspos(name.Data(), 0, backName.Data(), x, y, zBack, 0, "ONLY");
225 mc->Gspos(name.Data(), 0, frontName.Data(), x, y, zFront, 0, "ONLY");
229 // Divide the volume into sectors
231 name = Form(fgkSectorName, id);
232 mc->Gsdvn2(name.Data(), name2.Data(), 2, 2, -theta, siId);
234 // Divide the volume into strips
236 name = Form(fgkStripName, id);
237 mc->Gsdvt2(name.Data(), name2.Data(), dstrip, 1, stripoff, siId, ns);
238 sid = mc->VolId(name.Data());
239 AliDebug(10, Form("Got volume id %d for volume %s", sid, name.Data()));
243 case 'i': case 'I': fActiveId[0] = sid; break;
244 case 'o': case 'O': fActiveId[2] = sid; break;
253 // Create top of module shape
256 par[2] = siThick / 2;
258 name = Form(fgkModuleName, id);
260 mc->Gsvolu(name.Data(), "TRD1", siId, par, 4);
261 Int_t tid = mc->VolId(name.Data());
262 x = rmin + botL + topL / 2;
263 mc->Gspos(name.Data(), 0, backName.Data(), x, y, zBack, rot, "ONLY");
264 mc->Gspos(name.Data(), 0, frontName.Data(), x, y, zFront, rot, "ONLY");
267 // Create bottom of module shape
271 name = Form(fgkModuleName, id);
273 mc->Gsvolu(name.Data(), "TRD1", siId, par, 4);
274 Int_t bid = mc->VolId(name.Data());
276 z = - backWidth / 2 + siThick / 2;
277 mc->Gspos(name.Data(), 0, backName.Data(), x, y, zBack, rot, "ONLY");
278 mc->Gspos(name.Data(), 0, frontName.Data(), x, y, zFront, rot, "ONLY");
281 case 'i': case 'I': fActiveId[0] = tid; fActiveId[1] = bid; break;
282 case 'o': case 'O': fActiveId[2] = tid; fActiveId[3] = bid; break;
287 // Shape of Printed circuit Board
289 par[0] = c->Y() - off;
290 par[1] = b->Y() - off;
291 par[2] = pcbThick / 2;
293 x = rmin + botL + topL / 2;
294 zBack += siThick / 2 + space + pcbThick / 2;
295 zFront += siThick / 2 + space + pcbThick / 2;
296 name = Form(fgkPCBName, id, 'T');
297 mc->Gsvolu(name.Data(), "TRD1", pcbId, par, 4);
298 mc->Gspos(name.Data(), 0, backName.Data(), x, y, zBack, rot, "ONLY");
299 mc->Gspos(name.Data(), 0, frontName.Data(), x, y, zFront, rot, "ONLY");
302 par[0] = a->Y() - off;
303 par[1] = c->Y() - off;
305 name = Form(fgkPCBName, id, 'B');
307 mc->Gsvolu(name.Data(), "TRD1", pcbId, par, 4);
308 mc->Gspos(name.Data(), 0, backName.Data(), x, y, zBack, rot, "ONLY");
309 mc->Gspos(name.Data(), 0, frontName.Data(), x, y, zFront, rot, "ONLY");
316 x = a->X() + legoff + legr;
318 y1 = c->Y() - legoff - legr - off;
319 zBack += pcbThick / 2 + legl / 2;
320 zFront += pcbThick / 2 + legl / 2 + modSpace / 2;
321 name = Form(fgkShortLegName, id);
322 mc->Gsvolu(name.Data(), "TUBE", plaId, par, 3);
323 mc->Gspos(name.Data(), 0, backName.Data(), x, y, zBack, 0, "ONLY");
324 mc->Gspos(name.Data(), 1, backName.Data(), x1, y1, zBack, 0, "ONLY");
325 mc->Gspos(name.Data(), 2, backName.Data(), x1, -y1, zBack, 0, "ONLY");
328 par[2] += modSpace / 2;
329 name = Form(fgkLongLegName, id);
330 mc->Gsvolu(name.Data(), "TUBE", plaId, par, 3);
331 mc->Gspos(name.Data(), 0, frontName.Data(), x, y, zFront, 0, "ONLY");
332 mc->Gspos(name.Data(), 1, frontName.Data(), x1, y1, zFront, 0, "ONLY");
333 mc->Gspos(name.Data(), 2, frontName.Data(), x1, -y1, zFront, 0, "ONLY");
335 // Place modules+pcb+legs in ring volume
336 Int_t nmod = r->GetNModules();
337 name2 = Form(fgkRingName, id);
338 AliDebug(10, Form("making %d modules in ring %c", nmod, id));
339 for (Int_t i = 0; i < nmod; i++) {
340 Double_t th = (i + .5) * 2 * theta;
341 Bool_t isFront = (i % 2 == 0);
342 name = (isFront ? frontName : backName);
343 z = (isFront ? 0 : modSpace) / 2;
344 mc->Matrix(rot, 90, th, 90, fmod(90 + th, 360), 0, 0);
345 mc->Gspos(name.Data(), i, name2.Data(), 0, 0, z, rot, "ONLY");
351 //____________________________________________________________________
353 AliFMDG3Simulator::DetectorGeometry(AliFMDDetector* d, Double_t zmother)
355 // Common stuff for setting up the FMD1, FMD2, and FMD3 geometries.
356 // This includes putting the Honeycomb support plates and the rings
357 // into the mother volumes.
360 // d The detector geometry to use
361 // zmother The midpoint in global coordinates of detector vol.
366 if (!d) return kFALSE;
370 TVirtualMC* mc = TVirtualMC::GetMC();
372 // Loop over the defined rings
373 for (int i = 0; i < 2; i++) {
381 lowr = d->GetInnerHoneyLowR();
382 highr = d->GetInnerHoneyHighR();
387 lowr = d->GetOuterHoneyLowR();
388 highr = d->GetOuterHoneyHighR();
393 Char_t c = r->GetId();
394 Int_t id = d->GetId();
395 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
396 Int_t alId = (fFMD->GetIdtmed()->At(kAlId));
397 Double_t hcThick = d->GetHoneycombThickness();
398 Double_t alThick = d->GetAlThickness();
401 // Place ring in mother volume
402 if (zmother > 0) z = rz - zmother + r->GetRingDepth() / 2;
403 else z = zmother - rz + r->GetRingDepth() / 2;
404 name = Form(fgkRingName, c);
405 name2 = d->GetName();
406 mc->Gspos(name.Data(), Int_t(c), name2.Data(), 0, 0, z, 0, "ONLY");
408 // Place Top Honeycomb in mother volume
409 z += + r->GetRingDepth() / 2 + hcThick / 2;
413 par[2] = hcThick / 2;
416 name = Form(fgkTopHCName, id, c);
417 mc->Gsvolu(name.Data(), "TUBS", alId, par, 5);
418 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, z, 0, "ONLY");
422 par[2] -= alThick / 2;
424 name = Form(fgkTopIHCName, id, c);
425 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
426 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, 0, 0, "ONLY");
431 par[2] = hcThick / 2;
434 name2 = d->GetName();
435 name = Form(fgkBotHCName, id, c);
436 mc->Gsvolu(name.Data(), "TUBS", alId, par, 5);
437 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, z, 0, "ONLY");
441 par[2] -= alThick / 2;
443 name = Form(fgkBotIHCName, id, c);
444 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
445 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, 0, 0, "ONLY");
450 //____________________________________________________________________
452 AliFMDG3Simulator::FMD1Geometry(AliFMD1* fmd1)
454 // Setup the FMD1 geometry. The FMD1 only has one ring, and no
455 // special support as it is at the momement.
457 // See also AliFMDG3Simulator::DetectorGeometry
459 if (!fmd1) return kFALSE;
460 Double_t rmin = fmd1->GetInner()->GetLowR();
461 Double_t rmax = fmd1->GetInnerHoneyHighR();
462 Double_t hcThick = fmd1->GetHoneycombThickness();
463 Double_t w = fmd1->GetInner()->GetRingDepth() + hcThick;
464 Double_t z = fmd1->GetInnerZ() + w / 2;
465 TVirtualMC* mc = TVirtualMC::GetMC();
466 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
472 mc->Gsvolu(fmd1->GetName(), "TUBE", airId, par, 3);
473 mc->Gspos(fmd1->GetName(), fmd1->GetId(), "ALIC", 0, 0, z, 0, "ONLY");
475 return DetectorGeometry(fmd1, z);
478 //____________________________________________________________________
480 AliFMDG3Simulator::FMD2Geometry(AliFMD2* fmd2)
482 // Setup the FMD2 geometry. The FMD2 has no
483 // special support as it is at the momement.
485 // See also AliFMDG3Simulator::DetectorGeometry
487 if (!fmd2) return kFALSE;
488 Double_t rmin = fmd2->GetInner()->GetLowR();
489 Double_t rmax = fmd2->GetOuterHoneyHighR();
490 Double_t hcThick = fmd2->GetHoneycombThickness();
491 Double_t ow = fmd2->GetInner()->GetRingDepth();
492 Double_t iz = fmd2->GetInnerZ();
493 Double_t oz = fmd2->GetOuterZ();
494 Double_t w = TMath::Abs(oz - iz) + ow + hcThick;
495 Double_t z = oz + w / 2;
497 TVirtualMC* mc = TVirtualMC::GetMC();
498 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
504 mc->Gsvolu(fmd2->GetName(), "TUBE", airId, par, 3);
505 mc->Gspos(fmd2->GetName(), fmd2->GetId(), "ALIC", 0, 0, z, 0, "ONLY");
507 return DetectorGeometry(fmd2, z);
510 //____________________________________________________________________
512 AliFMDG3Simulator::FMD3Geometry(AliFMD3* fmd3)
514 // Setup the FMD3 geometry. The FMD2 has a rather elaborate support
515 // structure, as the support will also support the vacuum
518 // See also AliFMDG3Simulator::DetectorGeometry
520 if (!fmd3) return kFALSE;
521 Double_t nlen = fmd3->GetNoseLength();
522 Double_t nz = fmd3->GetNoseZ();
523 Double_t noser1 = fmd3->GetNoseLowR();
524 Double_t noser2 = fmd3->GetNoseHighR();
525 Double_t conel = fmd3->GetConeLength();
526 Double_t backl = fmd3->GetBackLength();
527 Double_t backr1 = fmd3->GetBackLowR();
528 Double_t backr2 = fmd3->GetBackHighR();
529 Double_t zdist = conel - backl - nlen;
530 Double_t tdist = backr2 - noser2;
531 Double_t beaml = TMath::Sqrt(zdist * zdist + tdist * tdist);
532 Double_t theta = -180. * TMath::ATan2(tdist, zdist) / TMath::Pi();
533 Double_t innerZ = fmd3->GetInnerZ();
534 Double_t innerZh = (innerZ - fmd3->GetInner()->GetRingDepth()
535 - fmd3->GetHoneycombThickness());
536 Double_t outerZ = fmd3->GetOuterZ();
537 Double_t outerZh = (outerZ - fmd3->GetOuter()->GetRingDepth()
538 - fmd3->GetHoneycombThickness());
539 Double_t innerr1 = fmd3->GetInner()->GetLowR();
540 // Double_t innerr2 = fmd3->GetInner()->GetHighR();
541 Double_t outerr1 = fmd3->GetOuter()->GetLowR();
542 // Double_t outerr2 = fmd3->GetOuter()->GetHighR();
543 Double_t flanger = fmd3->GetFlangeR();
544 Double_t minZ = TMath::Min(nz - conel, outerZh);
545 Double_t z = fmd3->GetZ();
547 TVirtualMC* mc = TVirtualMC::GetMC();
548 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
549 Int_t cId = (fFMD->GetIdtmed()->At(kCarbonId));
561 par[6] = z - (nz - nlen);
563 par[8] = fmd3->ConeR(z - par[6])+.15;
567 par[11] = fmd3->ConeR(z - par[9])+.15;
569 par[12] = z - innerZh;
571 par[14] = fmd3->ConeR(z - par[12])+.15;
575 par[17] = fmd3->ConeR(z - par[15])+.15;
577 par[18] = z - nz + zdist + nlen;
579 par[20] = fmd3->ConeR(z - par[18])+.15;
581 par[21] = z - nz + nlen + zdist;
583 par[23] = flanger+1.5;
587 par[26] = flanger+1.5;
588 mc->Gsvolu(fmd3->GetName(), "PCON", airId, par, 27);
591 mc->Matrix(id, 270, 180, 90, 90, 180, 0);
592 mc->Gspos(fmd3->GetName(), fmd3->GetId(), "ALIC", 0, 0, z, id, "ONLY");
598 zi = z - nz + nlen / 2;
599 mc->Gsvolu(fgkNoseName, "TUBE", cId, par, 3);
600 mc->Gspos(fgkNoseName, 0, fmd3->GetName(), 0, 0, zi, 0, "MANY");
606 zi = z - nz + conel - backl / 2;
607 mc->Gsvolu(fgkBackName, "TUBE", cId, par, 3);
608 mc->Gspos(fgkBackName, 0, fmd3->GetName(), 0, 0, zi, 0, "ONLY");
613 par[0] = (flanger - backr2) / 2;
614 par[1] = fmd3->GetBeamWidth() / 2;
616 mc->Gsvolu(fgkFlangeName, "BOX", cId, par, 3);
617 n = fmd3->GetNFlange();
618 r = backr2 + (flanger - backr2) / 2;
619 for (Int_t i = 0; i < n; i++) {
620 Double_t phi = 360. / n * i + 180. / n;
621 Double_t x = r * TMath::Cos(TMath::Pi() / 180 * phi);
622 Double_t y = r * TMath::Sin(TMath::Pi() / 180 * phi);
624 mc->Matrix(id, 90, phi, 90, 90 + phi, 0, 0);
625 mc->Gspos(fgkFlangeName, i, fmd3->GetName(), x, y, zi, id, "ONLY");
629 par[0] = fmd3->GetBeamThickness() / 2;
630 par[1] = fmd3->GetBeamWidth() / 2;
632 mc->Gsvolu(fgkBeamName, "BOX", cId, par, 3);
633 n = fmd3->GetNBeam();
634 r = noser2 + tdist / 2;
635 zi = z - nz + nlen + zdist / 2;
636 for (Int_t i = 0; i < n; i++) {
637 Double_t phi = 360. / n * i;
638 Double_t x = r * TMath::Cos(TMath::Pi() / 180 * phi);
639 Double_t y = r * TMath::Sin(TMath::Pi() / 180 * phi);
642 mc->Matrix(id, 90-theta, phi, 90, 90 + phi, 360 - theta, phi);
643 mc->Gspos(fgkBeamName, i, fmd3->GetName(), x, y, zi, id, "MANY");
646 return DetectorGeometry(fmd3, z);
649 //____________________________________________________________________
651 AliFMDG3Simulator::DefineGeometry()
653 // Setup up the FMD geometry.
654 AliDebug(10, "Setting up volume");
656 AliFMDGeometry* fmd = AliFMDGeometry::Instance();
657 if (!RingGeometry(fmd->GetInner())) {
658 AliError("Failed to create inner ring volume");
661 if (!RingGeometry(fmd->GetOuter())) {
662 AliError("Failed to create outer ring volume");
665 FMD1Geometry(fmd->GetFMD1());
666 FMD2Geometry(fmd->GetFMD2());
667 FMD3Geometry(fmd->GetFMD3());
670 //____________________________________________________________________