16#include "TGeoCompositeShape.h"
17#include "TGeoManager.h"
18#include "TGeoMaterial.h"
19#include "TGeoMedium.h"
24#include "TGeoUniformMagField.h"
25#include "TGeoVolume.h"
30#include "FairGeoBuilder.h"
31#include "FairGeoInterface.h"
32#include "FairGeoLoader.h"
33#include "FairGeoMedia.h"
34#include "FairGeoNode.h"
35#include "FairGeoVolume.h"
37#include "FairRuntimeDb.h"
38#include "FairVolume.h"
44#include "TVirtualMC.h"
47Double_t ycross(Double_t a, Double_t R, Double_t x) {
55 Double_t
A =
R *
R - (
x - a) * (x - a);
62Double_t integralSqrt(Double_t ynorm) {
70 1. / 2. * (ynorm * TMath::Sqrt(1 - ynorm * ynorm) + TMath::ASin(ynorm));
74Double_t fraction(Double_t R, Double_t x, Double_t y) {
84 Double_t F = 2 *
R *
R * (integralSqrt(y / R));
86 Double_t result = F / (
R *
R * TMath::Pi());
90Double_t area(Double_t a, Double_t R, Double_t xL, Double_t xR) {
103 if (xL <= a - R && xR >= a + R) {
107 Double_t leftC = ycross(a, R, xL);
108 Double_t rightC = ycross(a, R, xR);
109 if (leftC < 0 && rightC < 0) {
114 fracR = fraction(R, TMath::Abs(xR - a), rightC);
117 fracL = fraction(R, TMath::Abs(xL - a), leftC);
120 Double_t theAnswer = 0;
123 theAnswer += 1 - fracL;
133 theAnswer += 1 - fracR;
146 : Detector(name, Active,
kMTC) {}
149 Double_t width, Double_t height, Double_t fiber_tilt_angle,
150 Double_t iron_thickness, Double_t scifi_thickness,
151 Int_t num_of_agg_channels, Double_t scint_cell_size,
152 Double_t scint_thickness, Int_t number_of_layers, Double_t z_position,
153 Double_t field_strength) {
171 TGeoVolumeAssembly* modMotherVol,
172 Double_t z_shift, Double_t width,
173 Double_t height, Double_t thickness,
174 Double_t cellSizeX, Double_t cellSizeY,
175 TGeoMedium* material, Int_t color,
176 Double_t transparency, Int_t LayerId) {
177 modMotherVol->SetLineColor(color);
178 modMotherVol->SetTransparency(transparency);
179 auto scint_volume =
new TGeoVolumeAssembly(Form(
"%s_scint", name));
180 modMotherVol->AddNode(scint_volume, 0,
new TGeoTranslation(0, 0, z_shift));
181 auto scint_mat =
new TGeoVolumeAssembly(Form(
"%s_scint_mat", name));
182 scint_volume->AddNode(scint_mat, 0,
new TGeoTranslation(0, 0, 0));
183 auto cell =
new TGeoBBox(Form(
"%s_cell", name), cellSizeX / 2, cellSizeY / 2,
185 auto cellVol =
new TGeoVolume(Form(
"%s_cell", name), cell, material);
186 cellVol->SetLineColor(color);
187 cellVol->SetTransparency(transparency);
188 AddSensitiveVolume(cellVol);
189 Int_t nX = Int_t(width / cellSizeX);
190 Int_t nY = Int_t(height / cellSizeY);
192 for (Int_t i = 0; i < nX; i++) {
193 for (Int_t j = 0; j < nY; j++) {
194 Double_t x = -width / 2 + cellSizeX * (i + 0.5);
195 Double_t y = -height / 2 + cellSizeY * (j + 0.5);
196 scint_mat->AddNode(cellVol, 1e8 + 1e6 + 2e5 + 0e4 + i * nY + j,
197 new TGeoTranslation(x, y, 0));
203 TGeoVolumeAssembly* modMotherVol,
204 Double_t width, Double_t height,
205 Double_t thickness, Int_t LayerId) {
207 TGeoBBox* lowerIronBox =
new TGeoBBox(Form(
"%s_lowerIron", name), width / 2,
209 TGeoVolume* lowerIronVol =
new TGeoVolume(
210 Form(
"%s_lowerIron", name), lowerIronBox, gGeoManager->GetMedium(
"iron"));
211 lowerIronVol->SetLineColor(kGray + 1);
212 lowerIronVol->SetTransparency(20);
213 modMotherVol->AddNode(lowerIronVol, 0,
217 TGeoVolumeAssembly* ScifiVolU =
218 new TGeoVolumeAssembly(Form(
"%s_scifi_U", name));
219 modMotherVol->AddNode(ScifiVolU, 0,
new TGeoTranslation(0, 0, 0));
220 TGeoBBox* epoxyMatBoxU =
new TGeoBBox(Form(
"%s_epoxyMat", name), width / 2,
222 TGeoVolume* ScifiMatVolU =
new TGeoVolume(
223 Form(
"%s_epoxyMat", name), epoxyMatBoxU, gGeoManager->GetMedium(
"Epoxy"));
224 ScifiMatVolU->SetLineColor(kYellow - 2);
225 ScifiMatVolU->SetTransparency(30);
226 ScifiMatVolU->SetVisibility(kFALSE);
227 ScifiMatVolU->SetVisDaughters(kFALSE);
228 ScifiVolU->AddNode(ScifiMatVolU, 0,
new TGeoTranslation(0, 0,
zFiberMat1));
231 TGeoVolumeAssembly* ScifiVolV =
232 new TGeoVolumeAssembly(Form(
"%s_scifi_V", name));
233 modMotherVol->AddNode(ScifiVolV, 0,
new TGeoTranslation(0, 0, 0));
234 TGeoBBox* epoxyMatBoxV =
new TGeoBBox(Form(
"%s_epoxyMat", name), width / 2,
236 TGeoVolume* ScifiMatVolV =
new TGeoVolume(
237 Form(
"%s_epoxyMat", name), epoxyMatBoxV, gGeoManager->GetMedium(
"Epoxy"));
238 ScifiMatVolV->SetLineColor(kYellow - 2);
239 ScifiMatVolV->SetTransparency(30);
240 ScifiMatVolV->SetVisibility(kFALSE);
241 ScifiMatVolV->SetVisDaughters(kFALSE);
242 ScifiVolV->AddNode(ScifiMatVolV, 0,
new TGeoTranslation(0, 0,
zFiberMat2));
245 TGeoBBox* upperIronBox =
new TGeoBBox(Form(
"%s_upperIron", name), width / 2,
247 TGeoVolume* upperIronVol =
new TGeoVolume(
248 Form(
"%s_upperIron", name), upperIronBox, gGeoManager->GetMedium(
"iron"));
249 upperIronVol->SetLineColor(kGray + 1);
250 upperIronVol->SetTransparency(20);
251 modMotherVol->AddNode(upperIronVol, 0,
260 LOG(info) <<
"Fiber length set to " <<
fFiberLength <<
" cm";
264 TGeoTube* fiberTube =
266 TGeoVolume* fiberVol =
267 new TGeoVolume(
"FiberVol", fiberTube, gGeoManager->GetMedium(
"SciFiMat"));
268 AddSensitiveVolume(fiberVol);
269 fiberVol->SetLineColor(kMagenta);
270 fiberVol->SetTransparency(15);
271 fiberVol->SetVisibility(kFALSE);
274 TGeoRotation* rotU =
new TGeoRotation();
277 TGeoRotation* rotV =
new TGeoRotation();
283 Double_t z0 = -
fiberMatThick / 2 + (layer + 0.5) * (layerThick);
284 for (
int j = 0; j < fNumFibers; ++j) {
286 if (layer % 2 == 1) {
287 if (j == fNumFibers - 1) {
292 TGeoCombiTrans* ct =
new TGeoCombiTrans(
"", x0, 0, z0, rotU);
293 Int_t copyNo = 100000000 + 1000000 + 0 * 100000 + layer * 10000 + j;
294 ScifiMatVolU->AddNode(fiberVol, copyNo, ct);
299 for (
int layer = 0; layer < numFiberLayers; ++layer) {
300 Double_t z0 = -
fiberMatThick / 2 + (layer + 0.5) * (layerThick);
301 for (
int j = 0; j < fNumFibers; ++j) {
303 if (layer % 2 == 1) {
304 if (j == fNumFibers - 1) {
309 TGeoCombiTrans* ct =
new TGeoCombiTrans(
"", x0, 0, z0, rotV);
310 Int_t copyNo = 100000000 + 1000000 + 1 * 100000 + layer * 10000 + j;
311 ScifiMatVolV->AddNode(fiberVol, copyNo, ct);
321 TGeoMedium* air = gGeoManager->GetMedium(
"air");
322 TGeoMedium* ironMed = gGeoManager->GetMedium(
"iron");
325 TGeoMedium* scintMed = gGeoManager->GetMedium(
"SciFiMat");
332 Double_t totalLength =
fLayers * moduleSpacing;
337 new TGeoBBox(
"MTC_env",
fWidth / 2,
fHeight / 2, totalLength / 2);
338 auto envVol =
new TGeoVolume(
"MTC", envBox, air);
339 envVol->SetLineColor(kGreen);
340 envVol->SetTransparency(50);
345 auto ironVol =
new TGeoVolume(
"MTC_iron", ironBox, ironMed);
346 ironVol->SetLineColor(kGray + 1);
347 ironVol->SetTransparency(20);
349 if (
fFieldY != 0) ironVol->SetField(
new TGeoUniformMagField(0,
fFieldY, 0));
352 TGeoVolumeAssembly* sensitiveModule =
new TGeoVolumeAssembly(
"MTC_layer");
359 for (Int_t i = 0; i <
fLayers; i++) {
361 Double_t zPos = -totalLength / 2 + i * moduleSpacing;
365 envVol->AddNode(ironVol, i,
366 new TGeoTranslation(0, 0, zPos +
fIronThick / 2));
376 gGeoManager->GetTopVolume()->AddNode(envVol, 1,
377 new TGeoTranslation(0, 0,
fZCenter));
383 if (gMC->IsTrackEntering()) {
385 fTime = gMC->TrackTime() * 1.0e09;
387 gMC->TrackPosition(
fPos);
388 gMC->TrackMomentum(
fMom);
389 TGeoNavigator* nav = gGeoManager->GetCurrentNavigator();
390 Int_t vol_local_id = nav->GetCurrentNode()->GetNumber() %
392 Int_t layer_id = nav->GetMother(3)->GetNumber();
393 fVolumeID = 100000000 + layer_id * 1000000 +
400 if (gMC->IsTrackExiting() || gMC->IsTrackStop() ||
401 gMC->IsTrackDisappeared()) {
406 TParticle* p = gMC->GetStack()->GetCurrentTrack();
407 fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
408 Int_t pdgCode = p->GetPdgCode();
410 gMC->TrackPosition(Pos);
412 gMC->TrackMomentum(Mom);
415 x = (
fPos.X() + Pos.X()) / 2.;
416 y = (
fPos.Y() + Pos.Y()) / 2.;
417 z = (
fPos.Z() + Pos.Z()) / 2.;
421 z = (
fPos.Z() + Pos.Z()) / 2.;
429 stack->AddPoint(
kMTC);
435 if (gGeoManager->FindVolumeFast(
"SiPMmapVolU") ||
436 gGeoManager->FindVolumeFast(
"SiPMmapVolV")) {
443 LOG(warn) <<
"Number of SiPM channels (" <<
fNSiPMChan
445 <<
"), redistributing across multiple SiPMs";
448 std::ceil(
static_cast<double>(
fNSiPMChan) / kMaxChannelsPerSiPM));
450 LOG(info) <<
"Increasing number of SiPMs up to " <<
fNSiPMs;
456 LOG(info) <<
"New fNSiPMChan = " <<
fNSiPMChan;
459 Double_t firstChannelX = -
fWidth / 2;
461 LOG(info) <<
"SiPM Overlap parameters:\n"
462 <<
" fLengthScifiMat = " << fLengthScifiMat <<
" cm\n"
463 <<
" fWidthChannel = " << fWidthChannel <<
" cm\n"
465 <<
" fChannelAggregated = " << fChannelAggregated <<
"\n"
467 <<
" fNSiPMs = " <<
fNSiPMs <<
"\n"
468 <<
" fNMats = " <<
fNMats <<
"\n"
469 <<
" fEdge = " << fEdge <<
" cm\n"
470 <<
" firstChannelX = " << firstChannelX <<
" cm";
473 TGeoVolumeAssembly* SiPMmapVolU =
new TGeoVolumeAssembly(
"SiPMmapVolU");
474 TGeoVolumeAssembly* SiPMmapVolV =
new TGeoVolumeAssembly(
"SiPMmapVolV");
476 TGeoBBox* ChannelVol_box =
new TGeoBBox(
477 "ChannelVol", fWidthChannel / 2, fLengthScifiMat / 2,
fiberMatThick / 2);
478 TGeoVolume* ChannelVol =
new TGeoVolume(
"ChannelVol", ChannelVol_box,
479 gGeoManager->GetMedium(
"silicon"));
499 Double_t pos = fEdge + firstChannelX;
500 for (
int imat = 0; imat <
fNMats; imat++) {
501 for (
int isipms = 0; isipms <
fNSiPMs; isipms++) {
502 for (
int ichannel = 0; ichannel <
fNSiPMChan; ichannel++) {
504 SiPMmapVolU->AddNode(
505 ChannelVol, 100000 * 0 + imat * 10000 + isipms * 1000 + ichannel,
506 new TGeoTranslation(pos, 0, 0));
508 SiPMmapVolV->AddNode(
509 ChannelVol, 100000 * 1 + imat * 10000 + isipms * 1000 + ichannel,
510 new TGeoTranslation(-pos, 0, 0));
511 pos += fWidthChannel;
537 Int_t station_number =
static_cast<int>(fDetectorID / 1e6) % 100;
538 Int_t plane_type =
static_cast<int>(fDetectorID / 1e5) %
541 TString sID, stationID;
542 sID.Form(
"%i", fDetectorID);
543 stationID.Form(
"%i", station_number);
547 "/cave/MTC_1/MTC_layer_" + stationID +
548 ((plane_type == 0) ?
"/MTC_scifi_U_0/MTC_epoxyMat_0/FiberVol_1010"
549 :
"/MTC_scifi_V_0/MTC_epoxyMat_0/FiberVol_1011");
551 TGeoNavigator* nav = gGeoManager->GetCurrentNavigator();
553 TGeoNode* W = nav->GetCurrentNode();
554 TGeoBBox* S =
dynamic_cast<TGeoBBox*
>(W->GetVolume()->GetShape());
556 Double_t top[3] = {0, 0, (S->GetDZ())};
557 Double_t bot[3] = {0, 0, -(S->GetDZ())};
558 Double_t Gtop[3], Gbot[3];
559 nav->LocalToMaster(top, Gtop);
560 nav->LocalToMaster(bot, Gbot);
561 A.SetXYZ(Gtop[0], Gtop[1], Gtop[2]);
562 B.SetXYZ(Gbot[0], Gbot[1], Gbot[2]);
566 Int_t station_number =
static_cast<int>(fDetectorID / 1e6) % 100;
567 Int_t plane_type =
static_cast<int>(fDetectorID / 1e5) %
570 TString sID, stationID;
571 sID.Form(
"%i", fDetectorID);
572 stationID.Form(
"%i", station_number);
575 TString path =
"/cave/MTC_1/MTC_layer_" + stationID +
576 ((plane_type == 0) ?
"/MTC_scifi_U_0" :
"/MTC_scifi_V_0");
577 TGeoNavigator* nav = gGeoManager->GetCurrentNavigator();
582 nav->MasterToLocal(aglob, aloc);
583 return TVector3(aloc[0], aloc[1], aloc[2]);
606 Int_t locNumber = SiPMChan % 1000000;
607 Int_t station_number =
static_cast<int>(SiPMChan / 1e6) % 100;
608 Int_t plane_type =
static_cast<int>(SiPMChan / 1e5) %
615 stationID.Form(
"%i", station_number);
617 Double_t loc[3] = {0, 0, 0};
618 TString path =
"/cave/MTC_1/MTC_layer_" + stationID +
619 ((plane_type == 0) ?
"/MTC_scifi_U_0/MTC_epoxyMat_0"
620 :
"/MTC_scifi_V_0/MTC_epoxyMat_0");
621 TGeoNavigator* nav = gGeoManager->GetCurrentNavigator();
622 Double_t glob[3] = {0, 0, 0};
623 loc[0] = locPosition;
627 nav->LocalToMaster(loc, glob);
628 A.SetXYZ(glob[0], glob[1], glob[2]);
629 loc[0] = locPosition;
633 nav->LocalToMaster(loc, glob);
634 B.SetXYZ(glob[0], glob[1], glob[2]);
641 LOG(warning) <<
"SiPM mapping already done, skipping.";
644 Float_t fibresRadius = -1;
650 std::vector<std::pair<const char*, const char*>> sipm_planes = {
651 {
"SiPMmapVolU",
"MTC_scifi_U"}, {
"SiPMmapVolV",
"MTC_scifi_V"}};
652 for (
const auto& [sipm_vol, scifi_vol] : sipm_planes) {
653 auto sipm = gGeoManager->FindVolumeFast(sipm_vol);
655 TObjArray* Nodes = sipm->GetNodes();
656 auto plane = gGeoManager->FindVolumeFast(scifi_vol);
657 if (!plane)
continue;
658 for (
int imat = 0; imat < plane->GetNodes()->GetEntries(); imat++) {
659 auto mat =
static_cast<TGeoNode*
>(plane->GetNodes()->At(imat));
660 auto vmat = mat->GetVolume();
661 for (
int ifibre = 0; ifibre < vmat->GetNodes()->GetEntriesFast();
663 fibre =
static_cast<TGeoNode*
>(vmat->GetNodes()->At(ifibre));
664 if (fibresRadius < 0) {
665 auto tmp = fibre->GetVolume()->GetShape();
666 auto S =
dynamic_cast<TGeoBBox*
>(tmp);
667 fibresRadius = S->GetDX();
670 fibre->GetNumber() % 1000000 +
677 for (Int_t nChan = 0; nChan < Nodes->GetEntriesFast();
679 vol =
static_cast<TGeoNode*
>(Nodes->At(nChan));
680 Int_t N = vol->GetNumber();
681 Float_t xcentre = vol->GetMatrix()->GetTranslation()[0];
683 TGeoBBox*
B =
dynamic_cast<TGeoBBox*
>(vol->GetVolume()->GetShape());
687 if (TMath::Abs(xcentre - a) > 3 * dSiPM / 2) {
690 Float_t W = area(a, fibresRadius, xcentre - dSiPM, xcentre + dSiPM);
694 std::array<float, 2> Wa;
698 if (sipm_vol == std::string(
"SiPMmapVolU")) {
709 if (sipm_vol == std::string(
"SiPMmapVolU")) {
713 for (
auto [current_fibre, Wa] : it) {
720 for (
auto [N, it] : fibresSiPM_U) {
721 for (
auto [nfibre, Wa] : it) {
725 }
else if (sipm_vol == std::string(
"SiPMmapVolV")) {
729 for (
auto [current_fibre, Wa] : it) {
736 for (
auto [N, it] : fibresSiPM_V) {
737 for (
auto [nfibre, Wa] : it) {
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > siPMFibres_V
mapping of fibres to SiPM channels
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > fibresSiPM_V
inverse mapping
Double_t fSciFiBendingAngle
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > fibresSiPM_U
static constexpr Int_t kMaxChannelsPerSiPM
void ConstructGeometry() override
TVector3 GetLocalPos(Int_t fDetectorID, TVector3 *glob)
void SetMTCParameters(Double_t width, Double_t height, Double_t fiber_tilt_angle, Double_t iron_thickness, Double_t scifi_thickness, Int_t num_of_agg_channels, Double_t scint_cell_size, Double_t scint_thickness, Int_t number_of_layers, Double_t z_position, Double_t field_strength)
virtual void CreateScintModule(const char *name, TGeoVolumeAssembly *modMotherVol, Double_t z_shift, Double_t width, Double_t height, Double_t thickness, Double_t cellSizeX, Double_t cellSizeY, TGeoMedium *material, Int_t color, Double_t transparency, Int_t LayerId)
virtual void CreateSciFiModule(const char *name, TGeoVolumeAssembly *modMotherVol, Double_t width, Double_t height, Double_t thickness, Int_t LayerId)
void GetSiPMPosition(Int_t SiPMChan, TVector3 &A, TVector3 &B)
std::map< Int_t, float > SiPMPos_U
inverse mapping
Bool_t ProcessHits(FairVolume *vol=0) override
std::map< Int_t, float > SiPMPos_V
virtual void SiPMOverlap()
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > siPMFibres_U
mapping of fibres to SiPM channels
void GetPosition(Int_t fDetectorID, TVector3 &vLeft, TVector3 &vRight)
Int_t fTrackID
event index
Int_t fVolumeID
track index
TLorentzVector fPos
volume id
Double_t fTime
momentum at entrance
MTCDetPoint * AddHit(Args &&... args)
TLorentzVector fMom
position at entrance
Int_t InitMedium(const char *name)