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 // +--------------------+ +---------+---------+
44 // This defines the interface for the various parts of AliROOT that
45 // uses the FMD, like AliFMDSimulator, AliFMDDigitizer,
46 // AliFMDReconstructor, and so on.
49 // This is the base class for the FMD simulation tasks. The
50 // simulator tasks are responsible to implment the geoemtry, and
53 // * AliFMDGeoSimulator
54 // This is a concrete implementation of the AliFMDSimulator that
55 // uses the TGeo classes directly only. This defines the active
56 // volume as an ONLY XTRU shape with a divided MANY TUBS shape
57 // inside to implement the particular shape of the silicon
60 // * AliFMDG3Simulator
61 // This is a concrete implementation of the AliFMDSimulator that
62 // uses the TVirtualMC interface with GEANT 3.21-like messages.
63 // This implements the active volume as a divided TUBS shape. Hits
64 // in the corners should be cut away at run time (but currently
68 #include "AliFMDG3Simulator.h" // ALIFMDG3SIMULATOR_H
69 #include "AliFMDGeometry.h" // ALIFMDGEOMETRY_H
70 #include "AliFMDDetector.h" // ALIFMDDETECTOR_H
71 #include "AliFMDRing.h" // ALIFMDRING_H
72 #include "AliFMD1.h" // ALIFMD1_H
73 #include "AliFMD2.h" // ALIFMD2_H
74 #include "AliFMD3.h" // ALIFMD3_H
75 #include "AliFMD.h" // ALIFMD_H
76 #include <AliLog.h> // ALILOG_H
77 #include <TVector2.h> // ROOT_TVector2
78 #include <TVirtualMC.h> // ROOT_TVirtualMC
79 #include <TArrayI.h> // ROOT_TArrayI
81 //====================================================================
82 ClassImp(AliFMDG3Simulator)
84 ; // This is here to keep Emacs for indenting the next line
87 //____________________________________________________________________
88 AliFMDG3Simulator::AliFMDG3Simulator()
90 // Default constructor
97 //____________________________________________________________________
98 AliFMDG3Simulator::AliFMDG3Simulator(AliFMD* fmd, Bool_t detailed)
99 : AliFMDSimulator(fmd, detailed)
101 // Normal constructor
105 // fmd Pointer to AliFMD object
106 // detailed Whether to make a detailed simulation or not
114 //____________________________________________________________________
116 AliFMDG3Simulator::RingGeometry(AliFMDRing* r)
118 // Setup the geometry of a ring. The defined TGeoVolume is
119 // returned, and should be used when setting up the rest of the
124 // r Pointer to ring geometry object
130 AliError("Didn't get a ring object");
133 Char_t id = r->GetId();
134 Double_t siThick = r->GetSiThickness();
135 // const Int_t nv = r->GetNVerticies();
136 TVector2* a = r->GetVertex(5);
137 TVector2* b = r->GetVertex(3);
138 TVector2* c = r->GetVertex(4);
139 Double_t theta = r->GetTheta();
140 Double_t off = (TMath::Tan(TMath::Pi() * theta / 180)
141 * r->GetBondingWidth());
142 Double_t rmax = b->Mod();
143 Double_t rmin = r->GetLowR();
144 Double_t pcbThick = r->GetPrintboardThickness();
145 Double_t modSpace = r->GetModuleSpacing();
146 Double_t legr = r->GetLegRadius();
147 Double_t legl = r->GetLegLength();
148 Double_t legoff = r->GetLegOffset();
149 Int_t ns = r->GetNStrips();
150 Double_t stripoff = a->Mod();
151 Double_t dstrip = (rmax - stripoff) / ns;
155 TVirtualMC* mc = TVirtualMC::GetMC();
157 Int_t siId = fFMD->GetIdtmed()->At(kSiId);
158 Int_t airId = fFMD->GetIdtmed()->At(kAirId);
159 Int_t pcbId = fFMD->GetIdtmed()->At(kPcbId);
160 Int_t plaId = fFMD->GetIdtmed()->At(kPlasticId);
162 // Virtual volume shape to divide - This volume is only defined if
163 // the geometry is set to be detailed.
164 // Ring mother volume
167 par[2] = (siThick + pcbThick + legl + modSpace) / 2;
168 name = Form(fgkRingName, id);
169 mc->Gsvolu(name.Data(), "TUBE", airId, par, 3);
173 par[2] = siThick / 2;
176 name = Form(fgkActiveName, id);
177 mc->Gsvolu(name.Data(), "TUBS", (fDetailed ? airId : siId), par, 5);
182 name = Form(fgkSectorName, id);
183 mc->Gsdvn2(name.Data(), name2.Data(), 2, 2, -theta, airId);
186 name = Form(fgkStripName, id);
187 mc->Gsdvt2(name.Data(), name2.Data(), dstrip, 1, stripoff, siId, ns);
188 sid = mc->VolId(name.Data());
189 AliDebug(10, Form("Got volume id %d for volume %s", sid, name.Data()));
196 // fInnerV = moduleVolume->GetNumber();
201 // fOuterV = moduleVolume->GetNumber();
205 // Shape of Printed circuit Board
207 par[0] = c->Y() - off;
208 par[1] = b->Y() - off;
209 par[2] = pcbThick / 2;
210 par[3] = (b->X() - c->X()) / 2;
212 name = Form(fgkPCBName, id, 'T');
213 mc->Gsvolu(name.Data(), "TRD1", pcbId, par, 4);
215 par[0] = a->Y() - off;
216 par[1] = c->Y() - off;
217 par[3] = (c->X() - a->X()) / 2;
218 name = Form(fgkPCBName, id, 'B');
219 mc->Gsvolu(name.Data(), "TRD1", pcbId, par, 4);
225 name = Form(fgkShortLegName, id);
226 mc->Gsvolu(name.Data(), "TUBE", plaId, par, 3);
229 par[2] += modSpace / 2;
230 name = Form(fgkLongLegName, id);
231 mc->Gsvolu(name.Data(), "TUBE", plaId, par, 3);
233 // Back container volume
236 par[2] = (siThick + pcbThick + legl) / 2;
239 name = Form(fgkBackVName, id);
240 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
244 Double_t z = - par[2] + siThick / 2;
246 name = Form(fgkActiveName, id);
247 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, 0, "ONLY");
249 Double_t pbTopL = (b->X() - c->X());
250 Double_t pbBotL = (c->X() - a->X());
252 mc->Matrix(pbRot, 90, 90, 0, 90, 90, 0);
254 x = rmin + pbBotL + pbTopL / 2;
255 z += siThick / 2 + pcbThick / 2;
256 name = Form(fgkPCBName, id, 'T');
257 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, pbRot, "ONLY");
259 x = rmin + pbBotL / 2;
260 name = Form(fgkPCBName, id, 'B');
261 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, pbRot, "ONLY");
263 x = a->X() + legoff + legr;
265 z += pcbThick / 2 + legl / 2;
266 name = Form(fgkShortLegName, id);
267 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, 0, "ONLY");
270 y = c->Y() - legoff - legr - off;
271 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, 0, "ONLY");
274 mc->Gspos(name.Data(), 2, name2.Data(), x, y, z, 0, "ONLY");
277 // Front container volume
278 par[2] += modSpace / 2;
279 name = Form(fgkFrontVName, id);
280 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
284 z = - par[2] + siThick / 2;
286 name = Form(fgkActiveName, id);
287 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, 0, "ONLY");
289 pbTopL = (b->X() - c->X());
290 pbBotL = (c->X() - a->X());
291 x = rmin + pbBotL + pbTopL / 2;
292 z += siThick / 2 + pcbThick / 2;
293 name = Form(fgkPCBName, id, 'T');
294 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, pbRot, "ONLY");
296 x = rmin + pbBotL / 2;
297 name = Form(fgkPCBName, id, 'B');
298 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, pbRot, "ONLY");
300 x = a->X() + legoff + legr;
302 z += pcbThick / 2 + legl / 2 + modSpace / 2;
303 name = Form(fgkLongLegName, id);
304 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, 0, "ONLY");
307 y = c->Y() - legoff - legr - off;
308 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, 0, "ONLY");
311 mc->Gspos(name.Data(), 2, name2.Data(), x, y, z, 0, "ONLY");
315 Int_t nmod = r->GetNModules();
316 name2 = Form(fgkRingName, id);
317 AliDebug(10, Form("making %d modules in ring %c", nmod, id));
318 for (Int_t i = 0; i < nmod; i++) {
319 Double_t th = (i + .5) * 2 * theta;
320 Bool_t isFront = (i % 2 == 0);
321 name = (isFront ? Form(fgkFrontVName,id) :
322 Form(fgkBackVName,id));
323 Double_t z = (isFront ? 0 : modSpace) / 2;
325 mc->Matrix(rot, 90, th, 90, fmod(90 + th, 360), 0, 0);
326 mc->Gspos(name.Data(), i, name2.Data(), 0, 0, z, rot, "ONLY");
332 //____________________________________________________________________
334 AliFMDG3Simulator::DetectorGeometry(AliFMDDetector* d, Double_t zmother)
336 // Common stuff for setting up the FMD1, FMD2, and FMD3 geometries.
337 // This includes putting the Honeycomb support plates and the rings
338 // into the mother volumes.
341 // d The detector geometry to use
342 // zmother The midpoint in global coordinates of detector vol.
347 if (!d) return kFALSE;
351 TVirtualMC* mc = TVirtualMC::GetMC();
353 // Loop over the defined rings
354 for (int i = 0; i < 2; i++) {
362 lowr = d->GetInnerHoneyLowR();
363 highr = d->GetInnerHoneyHighR();
368 lowr = d->GetOuterHoneyLowR();
369 highr = d->GetOuterHoneyHighR();
374 Char_t c = r->GetId();
375 Int_t id = d->GetId();
376 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
377 Int_t alId = (fFMD->GetIdtmed()->At(kAlId));
378 Double_t hcThick = d->GetHoneycombThickness();
379 Double_t alThick = d->GetAlThickness();
382 // Place ring in mother volume
383 if (zmother > 0) z = rz - zmother + r->GetRingDepth() / 2;
384 else z = zmother - rz + r->GetRingDepth() / 2;
385 name = Form(fgkRingName, c);
386 name2 = d->GetName();
387 mc->Gspos(name.Data(), Int_t(c), name2.Data(), 0, 0, z, 0, "ONLY");
389 // Place Top Honeycomb in mother volume
390 z += + r->GetRingDepth() / 2 + hcThick / 2;
394 par[2] = hcThick / 2;
397 name = Form(fgkTopHCName, id, c);
398 mc->Gsvolu(name.Data(), "TUBS", alId, par, 5);
399 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, z, 0, "ONLY");
403 par[2] -= alThick / 2;
405 name = Form(fgkTopIHCName, id, c);
406 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
407 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, 0, 0, "ONLY");
412 par[2] = hcThick / 2;
415 name2 = d->GetName();
416 name = Form(fgkBotHCName, 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(fgkBotIHCName, 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 //____________________________________________________________________
433 AliFMDG3Simulator::FMD1Geometry(AliFMD1* fmd1)
435 // Setup the FMD1 geometry. The FMD1 only has one ring, and no
436 // special support as it is at the momement.
438 // See also AliFMDG3Simulator::DetectorGeometry
440 if (!fmd1) return kFALSE;
441 Double_t rmin = fmd1->GetInner()->GetLowR();
442 Double_t rmax = fmd1->GetInnerHoneyHighR();
443 Double_t hcThick = fmd1->GetHoneycombThickness();
444 Double_t w = fmd1->GetInner()->GetRingDepth() + hcThick;
445 Double_t z = fmd1->GetInnerZ() + w / 2;
446 TVirtualMC* mc = TVirtualMC::GetMC();
447 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
453 mc->Gsvolu(fmd1->GetName(), "TUBE", airId, par, 3);
454 mc->Gspos(fmd1->GetName(), fmd1->GetId(), "ALIC", 0, 0, z, 0, "ONLY");
456 return DetectorGeometry(fmd1, z);
459 //____________________________________________________________________
461 AliFMDG3Simulator::FMD2Geometry(AliFMD2* fmd2)
463 // Setup the FMD2 geometry. The FMD2 has no
464 // special support as it is at the momement.
466 // See also AliFMDG3Simulator::DetectorGeometry
468 if (!fmd2) return kFALSE;
469 Double_t rmin = fmd2->GetInner()->GetLowR();
470 Double_t rmax = fmd2->GetOuterHoneyHighR();
471 Double_t hcThick = fmd2->GetHoneycombThickness();
472 Double_t ow = fmd2->GetInner()->GetRingDepth();
473 Double_t iz = fmd2->GetInnerZ();
474 Double_t oz = fmd2->GetOuterZ();
475 Double_t w = TMath::Abs(oz - iz) + ow + hcThick;
476 Double_t z = oz + w / 2;
478 TVirtualMC* mc = TVirtualMC::GetMC();
479 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
485 mc->Gsvolu(fmd2->GetName(), "TUBE", airId, par, 3);
486 mc->Gspos(fmd2->GetName(), fmd2->GetId(), "ALIC", 0, 0, z, 0, "ONLY");
488 return DetectorGeometry(fmd2, z);
491 //____________________________________________________________________
493 AliFMDG3Simulator::FMD3Geometry(AliFMD3* fmd3)
495 // Setup the FMD3 geometry. The FMD2 has a rather elaborate support
496 // structure, as the support will also support the vacuum
499 // See also AliFMDG3Simulator::DetectorGeometry
501 if (!fmd3) return kFALSE;
502 Double_t nlen = fmd3->GetNoseLength();
503 Double_t nz = fmd3->GetNoseZ();
504 Double_t noser1 = fmd3->GetNoseLowR();
505 Double_t noser2 = fmd3->GetNoseHighR();
506 Double_t conel = fmd3->GetConeLength();
507 Double_t backl = fmd3->GetBackLength();
508 Double_t backr1 = fmd3->GetBackLowR();
509 Double_t backr2 = fmd3->GetBackHighR();
510 Double_t zdist = conel - backl - nlen;
511 Double_t tdist = backr2 - noser2;
512 Double_t beaml = TMath::Sqrt(zdist * zdist + tdist * tdist);
513 Double_t theta = -180. * TMath::ATan2(tdist, zdist) / TMath::Pi();
514 Double_t innerZ = fmd3->GetInnerZ();
515 Double_t innerZh = (innerZ - fmd3->GetInner()->GetRingDepth()
516 - fmd3->GetHoneycombThickness());
517 Double_t outerZ = fmd3->GetOuterZ();
518 Double_t outerZh = (outerZ - fmd3->GetOuter()->GetRingDepth()
519 - fmd3->GetHoneycombThickness());
520 Double_t innerr1 = fmd3->GetInner()->GetLowR();
521 // Double_t innerr2 = fmd3->GetInner()->GetHighR();
522 Double_t outerr1 = fmd3->GetOuter()->GetLowR();
523 // Double_t outerr2 = fmd3->GetOuter()->GetHighR();
524 Double_t flanger = fmd3->GetFlangeR();
525 Double_t minZ = TMath::Min(nz - conel, outerZh);
526 Double_t z = fmd3->GetZ();
528 TVirtualMC* mc = TVirtualMC::GetMC();
529 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
530 Int_t cId = (fFMD->GetIdtmed()->At(kCarbonId));
542 par[6] = z - (nz - nlen);
544 par[8] = fmd3->ConeR(z - par[6])+.15;
548 par[11] = fmd3->ConeR(z - par[9])+.15;
550 par[12] = z - innerZh;
552 par[14] = fmd3->ConeR(z - par[12])+.15;
556 par[17] = fmd3->ConeR(z - par[15])+.15;
558 par[18] = z - nz + zdist + nlen;
560 par[20] = fmd3->ConeR(z - par[18])+.15;
562 par[21] = z - nz + nlen + zdist;
564 par[23] = flanger+1.5;
568 par[26] = flanger+1.5;
569 mc->Gsvolu(fmd3->GetName(), "PCON", airId, par, 27);
572 mc->Matrix(id, 270, 180, 90, 90, 180, 0);
573 mc->Gspos(fmd3->GetName(), fmd3->GetId(), "ALIC", 0, 0, z, id, "ONLY");
579 zi = z - nz + nlen / 2;
580 mc->Gsvolu(fgkNoseName, "TUBE", cId, par, 3);
581 mc->Gspos(fgkNoseName, 0, fmd3->GetName(), 0, 0, zi, 0, "MANY");
587 zi = z - nz + conel - backl / 2;
588 mc->Gsvolu(fgkBackName, "TUBE", cId, par, 3);
589 mc->Gspos(fgkBackName, 0, fmd3->GetName(), 0, 0, zi, 0, "ONLY");
594 par[0] = (flanger - backr2) / 2;
595 par[1] = fmd3->GetBeamWidth() / 2;
597 mc->Gsvolu(fgkFlangeName, "BOX", cId, par, 3);
598 n = fmd3->GetNFlange();
599 r = backr2 + (flanger - backr2) / 2;
600 for (Int_t i = 0; i < n; i++) {
601 Double_t phi = 360. / n * i + 180. / n;
602 Double_t x = r * TMath::Cos(TMath::Pi() / 180 * phi);
603 Double_t y = r * TMath::Sin(TMath::Pi() / 180 * phi);
605 mc->Matrix(id, 90, phi, 90, 90 + phi, 0, 0);
606 mc->Gspos(fgkFlangeName, i, fmd3->GetName(), x, y, zi, id, "ONLY");
610 par[0] = fmd3->GetBeamThickness() / 2;
611 par[1] = fmd3->GetBeamWidth() / 2;
613 mc->Gsvolu(fgkBeamName, "BOX", cId, par, 3);
614 n = fmd3->GetNBeam();
615 r = noser2 + tdist / 2;
616 zi = z - nz + nlen + zdist / 2;
617 for (Int_t i = 0; i < n; i++) {
618 Double_t phi = 360. / n * i;
619 Double_t x = r * TMath::Cos(TMath::Pi() / 180 * phi);
620 Double_t y = r * TMath::Sin(TMath::Pi() / 180 * phi);
623 mc->Matrix(id, 90-theta, phi, 90, 90 + phi, 360 - theta, phi);
624 mc->Gspos(fgkBeamName, i, fmd3->GetName(), x, y, zi, id, "MANY");
627 return DetectorGeometry(fmd3, z);
630 //____________________________________________________________________
632 AliFMDG3Simulator::DefineGeometry()
634 // Setup up the FMD geometry.
635 AliDebug(10, "Setting up volume");
637 AliFMDGeometry* fmd = AliFMDGeometry::Instance();
638 if (!RingGeometry(fmd->GetInner())) {
639 AliError("Failed to create inner ring volume");
642 if (!RingGeometry(fmd->GetOuter())) {
643 AliError("Failed to create outer ring volume");
646 FMD1Geometry(fmd->GetFMD1());
647 FMD2Geometry(fmd->GetFMD2());
648 FMD3Geometry(fmd->GetFMD3());
651 //____________________________________________________________________