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
67 #include "AliFMDG3Simulator.h" // ALIFMDG3SIMULATOR_H
68 #include "AliFMDGeometry.h" // ALIFMDGEOMETRY_H
69 #include "AliFMDDetector.h" // ALIFMDDETECTOR_H
70 #include "AliFMDRing.h" // ALIFMDRING_H
71 #include "AliFMD1.h" // ALIFMD1_H
72 #include "AliFMD2.h" // ALIFMD2_H
73 #include "AliFMD3.h" // ALIFMD3_H
74 #include "AliFMD.h" // ALIFMD_H
75 #include <AliLog.h> // ALILOG_H
76 #include <TVector2.h> // ROOT_TVector2
77 #include <TVirtualMC.h> // ROOT_TVirtualMC
78 #include <TArrayI.h> // ROOT_TArrayI
80 //====================================================================
81 ClassImp(AliFMDG3Simulator)
83 ; // This is here to keep Emacs for indenting the next line
86 //____________________________________________________________________
87 AliFMDG3Simulator::AliFMDG3Simulator()
89 // Default constructor
96 //____________________________________________________________________
97 AliFMDG3Simulator::AliFMDG3Simulator(AliFMD* fmd, Bool_t detailed)
98 : AliFMDSimulator(fmd, detailed)
100 // Normal constructor
104 // fmd Pointer to AliFMD object
105 // detailed Whether to make a detailed simulation or not
113 //____________________________________________________________________
115 AliFMDG3Simulator::RingGeometry(AliFMDRing* r)
117 // Setup the geometry of a ring. The defined TGeoVolume is
118 // returned, and should be used when setting up the rest of the
123 // r Pointer to ring geometry object
129 AliError("Didn't get a ring object");
132 Char_t id = r->GetId();
133 Double_t siThick = r->GetSiThickness();
134 // const Int_t nv = r->GetNVerticies();
135 TVector2* a = r->GetVertex(5);
136 TVector2* b = r->GetVertex(3);
137 TVector2* c = r->GetVertex(4);
138 Double_t theta = r->GetTheta();
139 Double_t off = (TMath::Tan(TMath::Pi() * theta / 180)
140 * r->GetBondingWidth());
141 Double_t rmax = b->Mod();
142 Double_t rmin = r->GetLowR();
143 Double_t pcbThick = r->GetPrintboardThickness();
144 Double_t modSpace = r->GetModuleSpacing();
145 Double_t legr = r->GetLegRadius();
146 Double_t legl = r->GetLegLength();
147 Double_t legoff = r->GetLegOffset();
148 Int_t ns = r->GetNStrips();
149 Double_t stripoff = a->Mod();
150 Double_t dstrip = (rmax - stripoff) / ns;
154 TVirtualMC* mc = TVirtualMC::GetMC();
156 Int_t siId = fFMD->GetIdtmed()->At(kSiId);
157 Int_t airId = fFMD->GetIdtmed()->At(kAirId);
158 Int_t pcbId = fFMD->GetIdtmed()->At(kPcbId);
159 Int_t plaId = fFMD->GetIdtmed()->At(kPlasticId);
161 // Virtual volume shape to divide - This volume is only defined if
162 // the geometry is set to be detailed.
163 // Ring mother volume
166 par[2] = (siThick + pcbThick + legl + modSpace) / 2;
167 name = Form(fgkRingName, id);
168 mc->Gsvolu(name.Data(), "TUBE", airId, par, 3);
172 par[2] = siThick / 2;
175 name = Form(fgkActiveName, id);
176 mc->Gsvolu(name.Data(), "TUBS", (fDetailed ? airId : siId), par, 5);
181 name = Form(fgkSectorName, id);
182 mc->Gsdvn2(name.Data(), name2.Data(), 2, 2, -theta, airId);
185 name = Form(fgkStripName, id);
186 mc->Gsdvt2(name.Data(), name2.Data(), dstrip, 1, stripoff, siId, ns);
187 sid = mc->VolId(name.Data());
188 AliDebug(10, Form("Got volume id %d for volume %s", sid, name.Data()));
195 // fInnerV = moduleVolume->GetNumber();
200 // fOuterV = moduleVolume->GetNumber();
204 // Shape of Printed circuit Board
206 par[0] = c->Y() - off;
207 par[1] = b->Y() - off;
208 par[2] = pcbThick / 2;
209 par[3] = (b->X() - c->X()) / 2;
211 name = Form(fgkPCBName, id, 'T');
212 mc->Gsvolu(name.Data(), "TRD1", pcbId, par, 4);
214 par[0] = a->Y() - off;
215 par[1] = c->Y() - off;
216 par[3] = (c->X() - a->X()) / 2;
217 name = Form(fgkPCBName, id, 'B');
218 mc->Gsvolu(name.Data(), "TRD1", pcbId, par, 4);
224 name = Form(fgkShortLegName, id);
225 mc->Gsvolu(name.Data(), "TUBE", plaId, par, 3);
228 par[2] += modSpace / 2;
229 name = Form(fgkLongLegName, id);
230 mc->Gsvolu(name.Data(), "TUBE", plaId, par, 3);
232 // Back container volume
235 par[2] = (siThick + pcbThick + legl) / 2;
238 name = Form(fgkBackVName, id);
239 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
243 Double_t z = - par[2] + siThick / 2;
245 name = Form(fgkActiveName, id);
246 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, 0, "ONLY");
248 Double_t pbTopL = (b->X() - c->X());
249 Double_t pbBotL = (c->X() - a->X());
251 mc->Matrix(pbRot, 90, 90, 0, 90, 90, 0);
253 x = rmin + pbBotL + pbTopL / 2;
254 z += siThick / 2 + pcbThick / 2;
255 name = Form(fgkPCBName, id, 'T');
256 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, pbRot, "ONLY");
258 x = rmin + pbBotL / 2;
259 name = Form(fgkPCBName, id, 'B');
260 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, pbRot, "ONLY");
262 x = a->X() + legoff + legr;
264 z += pcbThick / 2 + legl / 2;
265 name = Form(fgkShortLegName, id);
266 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, 0, "ONLY");
269 y = c->Y() - legoff - legr - off;
270 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, 0, "ONLY");
273 mc->Gspos(name.Data(), 2, name2.Data(), x, y, z, 0, "ONLY");
276 // Front container volume
277 par[2] += modSpace / 2;
278 name = Form(fgkFrontVName, id);
279 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
283 z = - par[2] + siThick / 2;
285 name = Form(fgkActiveName, id);
286 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, 0, "ONLY");
288 pbTopL = (b->X() - c->X());
289 pbBotL = (c->X() - a->X());
290 x = rmin + pbBotL + pbTopL / 2;
291 z += siThick / 2 + pcbThick / 2;
292 name = Form(fgkPCBName, id, 'T');
293 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, pbRot, "ONLY");
295 x = rmin + pbBotL / 2;
296 name = Form(fgkPCBName, id, 'B');
297 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, pbRot, "ONLY");
299 x = a->X() + legoff + legr;
301 z += pcbThick / 2 + legl / 2 + modSpace / 2;
302 name = Form(fgkLongLegName, id);
303 mc->Gspos(name.Data(), 0, name2.Data(), x, y, z, 0, "ONLY");
306 y = c->Y() - legoff - legr - off;
307 mc->Gspos(name.Data(), 1, name2.Data(), x, y, z, 0, "ONLY");
310 mc->Gspos(name.Data(), 2, name2.Data(), x, y, z, 0, "ONLY");
314 Int_t nmod = r->GetNModules();
315 name2 = Form(fgkRingName, id);
316 AliDebug(10, Form("making %d modules in ring %c", nmod, id));
317 for (Int_t i = 0; i < nmod; i++) {
318 Double_t th = (i + .5) * 2 * theta;
319 Bool_t isFront = (i % 2 == 0);
320 name = (isFront ? Form(fgkFrontVName,id) :
321 Form(fgkBackVName,id));
322 Double_t z = (isFront ? 0 : modSpace) / 2;
324 mc->Matrix(rot, 90, th, 90, fmod(90 + th, 360), 0, 0);
325 mc->Gspos(name.Data(), i, name2.Data(), 0, 0, z, rot, "ONLY");
331 //____________________________________________________________________
333 AliFMDG3Simulator::DetectorGeometry(AliFMDDetector* d, Double_t zmother)
335 // Common stuff for setting up the FMD1, FMD2, and FMD3 geometries.
336 // This includes putting the Honeycomb support plates and the rings
337 // into the mother volumes.
340 // d The detector geometry to use
341 // zmother The midpoint in global coordinates of detector vol.
346 if (!d) return kFALSE;
350 TVirtualMC* mc = TVirtualMC::GetMC();
352 // Loop over the defined rings
353 for (int i = 0; i < 2; i++) {
361 lowr = d->GetInnerHoneyLowR();
362 highr = d->GetInnerHoneyHighR();
367 lowr = d->GetOuterHoneyLowR();
368 highr = d->GetOuterHoneyHighR();
373 Char_t c = r->GetId();
374 Int_t id = d->GetId();
375 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
376 Int_t alId = (fFMD->GetIdtmed()->At(kAlId));
377 Double_t hcThick = d->GetHoneycombThickness();
378 Double_t alThick = d->GetAlThickness();
381 // Place ring in mother volume
382 if (zmother > 0) z = rz - zmother + r->GetRingDepth() / 2;
383 else z = zmother - rz + r->GetRingDepth() / 2;
384 name = Form(fgkRingName, c);
385 name2 = d->GetName();
386 mc->Gspos(name.Data(), Int_t(c), name2.Data(), 0, 0, z, 0, "ONLY");
388 // Place Top Honeycomb in mother volume
389 z += + r->GetRingDepth() / 2 + hcThick / 2;
393 par[2] = hcThick / 2;
396 name = Form(fgkTopHCName, id, c);
397 mc->Gsvolu(name.Data(), "TUBS", alId, par, 5);
398 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, z, 0, "ONLY");
402 par[2] -= alThick / 2;
404 name = Form(fgkTopIHCName, id, c);
405 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
406 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, 0, 0, "ONLY");
411 par[2] = hcThick / 2;
414 name2 = d->GetName();
415 name = Form(fgkBotHCName, id, c);
416 mc->Gsvolu(name.Data(), "TUBS", alId, par, 5);
417 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, z, 0, "ONLY");
421 par[2] -= alThick / 2;
423 name = Form(fgkBotIHCName, id, c);
424 mc->Gsvolu(name.Data(), "TUBS", airId, par, 5);
425 mc->Gspos(name.Data(), 0, name2.Data(), 0, 0, 0, 0, "ONLY");
430 //____________________________________________________________________
432 AliFMDG3Simulator::FMD1Geometry(AliFMD1* fmd1)
434 // Setup the FMD1 geometry. The FMD1 only has one ring, and no
435 // special support as it is at the momement.
437 // See also AliFMDG3Simulator::DetectorGeometry
439 if (!fmd1) return kFALSE;
440 Double_t rmin = fmd1->GetInner()->GetLowR();
441 Double_t rmax = fmd1->GetInnerHoneyHighR();
442 Double_t hcThick = fmd1->GetHoneycombThickness();
443 Double_t w = fmd1->GetInner()->GetRingDepth() + hcThick;
444 Double_t z = fmd1->GetInnerZ() + w / 2;
445 TVirtualMC* mc = TVirtualMC::GetMC();
446 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
452 mc->Gsvolu(fmd1->GetName(), "TUBE", airId, par, 3);
453 mc->Gspos(fmd1->GetName(), fmd1->GetId(), "ALIC", 0, 0, z, 0, "ONLY");
455 return DetectorGeometry(fmd1, z);
458 //____________________________________________________________________
460 AliFMDG3Simulator::FMD2Geometry(AliFMD2* fmd2)
462 // Setup the FMD2 geometry. The FMD2 has no
463 // special support as it is at the momement.
465 // See also AliFMDG3Simulator::DetectorGeometry
467 if (!fmd2) return kFALSE;
468 Double_t rmin = fmd2->GetInner()->GetLowR();
469 Double_t rmax = fmd2->GetOuterHoneyHighR();
470 Double_t hcThick = fmd2->GetHoneycombThickness();
471 Double_t ow = fmd2->GetInner()->GetRingDepth();
472 Double_t iz = fmd2->GetInnerZ();
473 Double_t oz = fmd2->GetOuterZ();
474 Double_t w = TMath::Abs(oz - iz) + ow + hcThick;
475 Double_t z = oz + w / 2;
477 TVirtualMC* mc = TVirtualMC::GetMC();
478 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
484 mc->Gsvolu(fmd2->GetName(), "TUBE", airId, par, 3);
485 mc->Gspos(fmd2->GetName(), fmd2->GetId(), "ALIC", 0, 0, z, 0, "ONLY");
487 return DetectorGeometry(fmd2, z);
490 //____________________________________________________________________
492 AliFMDG3Simulator::FMD3Geometry(AliFMD3* fmd3)
494 // Setup the FMD3 geometry. The FMD2 has a rather elaborate support
495 // structure, as the support will also support the vacuum
498 // See also AliFMDG3Simulator::DetectorGeometry
500 if (!fmd3) return kFALSE;
501 Double_t nlen = fmd3->GetNoseLength();
502 Double_t nz = fmd3->GetNoseZ();
503 Double_t noser1 = fmd3->GetNoseLowR();
504 Double_t noser2 = fmd3->GetNoseHighR();
505 Double_t conel = fmd3->GetConeLength();
506 Double_t backl = fmd3->GetBackLength();
507 Double_t backr1 = fmd3->GetBackLowR();
508 Double_t backr2 = fmd3->GetBackHighR();
509 Double_t zdist = conel - backl - nlen;
510 Double_t tdist = backr2 - noser2;
511 Double_t beaml = TMath::Sqrt(zdist * zdist + tdist * tdist);
512 Double_t theta = -180. * TMath::ATan2(tdist, zdist) / TMath::Pi();
513 Double_t innerZ = fmd3->GetInnerZ();
514 Double_t innerZh = (innerZ - fmd3->GetInner()->GetRingDepth()
515 - fmd3->GetHoneycombThickness());
516 Double_t outerZ = fmd3->GetOuterZ();
517 Double_t outerZh = (outerZ - fmd3->GetOuter()->GetRingDepth()
518 - fmd3->GetHoneycombThickness());
519 Double_t innerr1 = fmd3->GetInner()->GetLowR();
520 // Double_t innerr2 = fmd3->GetInner()->GetHighR();
521 Double_t outerr1 = fmd3->GetOuter()->GetLowR();
522 // Double_t outerr2 = fmd3->GetOuter()->GetHighR();
523 Double_t flanger = fmd3->GetFlangeR();
524 Double_t minZ = TMath::Min(nz - conel, outerZh);
525 Double_t z = fmd3->GetZ();
527 TVirtualMC* mc = TVirtualMC::GetMC();
528 Int_t airId = (fFMD->GetIdtmed()->At(kAirId));
529 Int_t cId = (fFMD->GetIdtmed()->At(kCarbonId));
541 par[6] = z - (nz - nlen);
543 par[8] = fmd3->ConeR(z - par[6])+.15;
547 par[11] = fmd3->ConeR(z - par[9])+.15;
549 par[12] = z - innerZh;
551 par[14] = fmd3->ConeR(z - par[12])+.15;
555 par[17] = fmd3->ConeR(z - par[15])+.15;
557 par[18] = z - nz + zdist + nlen;
559 par[20] = fmd3->ConeR(z - par[18])+.15;
561 par[21] = z - nz + nlen + zdist;
563 par[23] = flanger+1.5;
567 par[26] = flanger+1.5;
568 mc->Gsvolu(fmd3->GetName(), "PCON", airId, par, 27);
571 mc->Matrix(id, 270, 180, 90, 90, 180, 0);
572 mc->Gspos(fmd3->GetName(), fmd3->GetId(), "ALIC", 0, 0, z, id, "ONLY");
578 zi = z - nz + nlen / 2;
579 mc->Gsvolu(fgkNoseName, "TUBE", cId, par, 3);
580 mc->Gspos(fgkNoseName, 0, fmd3->GetName(), 0, 0, zi, 0, "MANY");
586 zi = z - nz + conel - backl / 2;
587 mc->Gsvolu(fgkBackName, "TUBE", cId, par, 3);
588 mc->Gspos(fgkBackName, 0, fmd3->GetName(), 0, 0, zi, 0, "ONLY");
593 par[0] = (flanger - backr2) / 2;
594 par[1] = fmd3->GetBeamWidth() / 2;
596 mc->Gsvolu(fgkFlangeName, "BOX", cId, par, 3);
597 n = fmd3->GetNFlange();
598 r = backr2 + (flanger - backr2) / 2;
599 for (Int_t i = 0; i < n; i++) {
600 Double_t phi = 360. / n * i + 180. / n;
601 Double_t x = r * TMath::Cos(TMath::Pi() / 180 * phi);
602 Double_t y = r * TMath::Sin(TMath::Pi() / 180 * phi);
604 mc->Matrix(id, 90, phi, 90, 90 + phi, 0, 0);
605 mc->Gspos(fgkFlangeName, i, fmd3->GetName(), x, y, zi, id, "ONLY");
609 par[0] = fmd3->GetBeamThickness() / 2;
610 par[1] = fmd3->GetBeamWidth() / 2;
612 mc->Gsvolu(fgkBeamName, "BOX", cId, par, 3);
613 n = fmd3->GetNBeam();
614 r = noser2 + tdist / 2;
615 zi = z - nz + nlen + zdist / 2;
616 for (Int_t i = 0; i < n; i++) {
617 Double_t phi = 360. / n * i;
618 Double_t x = r * TMath::Cos(TMath::Pi() / 180 * phi);
619 Double_t y = r * TMath::Sin(TMath::Pi() / 180 * phi);
622 mc->Matrix(id, 90-theta, phi, 90, 90 + phi, 360 - theta, phi);
623 mc->Gspos(fgkBeamName, i, fmd3->GetName(), x, y, zi, id, "MANY");
626 return DetectorGeometry(fmd3, z);
629 //____________________________________________________________________
631 AliFMDG3Simulator::DefineGeometry()
633 // Setup up the FMD geometry.
634 AliDebug(10, "Setting up volume");
636 AliFMDGeometry* fmd = AliFMDGeometry::Instance();
637 if (!RingGeometry(fmd->GetInner())) {
638 AliError("Failed to create inner ring volume");
641 if (!RingGeometry(fmd->GetOuter())) {
642 AliError("Failed to create outer ring volume");
645 FMD1Geometry(fmd->GetFMD1());
646 FMD2Geometry(fmd->GetFMD2());
647 FMD3Geometry(fmd->GetFMD3());
650 //____________________________________________________________________