FairShip
Loading...
Searching...
No Matches
MTCDetector Class Reference

#include <MTCDetector.h>

Inheritance diagram for MTCDetector:
Collaboration diagram for MTCDetector:

Public Member Functions

 MTCDetector (const char *name, Bool_t Active, const char *Title="", Int_t DetId=0)
 
 MTCDetector ()
 
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 ConstructGeometry () override
 
void GetPosition (Int_t fDetectorID, TVector3 &vLeft, TVector3 &vRight)
 
TVector3 GetLocalPos (Int_t fDetectorID, TVector3 *glob)
 
void GetSiPMPosition (Int_t SiPMChan, TVector3 &A, TVector3 &B)
 
void SiPMmapping ()
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > GetSiPMmapU ()
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > GetFibresMapU ()
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > GetSiPMmapV ()
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > GetFibresMapV ()
 
std::map< Int_t, float > GetSiPMPos_U ()
 
std::map< Int_t, float > GetSiPMPos_V ()
 
Int_t Get_NSiPMChan () const
 
Float_t Get_SciFiActiveX () const
 
virtual void SiPMOverlap ()
 
Bool_t ProcessHits (FairVolume *vol=0) override
 
- Public Member Functions inherited from SHiP::Detector< MTCDetPoint >
 Detector ()=default
 
 Detector (const char *Name, Bool_t Active, Int_t detID)
 
 Detector (const char *Name, Bool_t Active)
 
 ~Detector () override=default
 
MTCDetPointAddHit (Args &&... args)
 
void ConstructGeometry () override=0
 
void Initialize () override
 
void Reset () override
 
void EndOfEvent () override
 
void Register () override
 
TClonesArray * GetCollection (Int_t iColl) const override
 
void UpdatePointTrackIndices (const std::map< Int_t, Int_t > &indexMap) override
 Update track indices in point collection after track filtering.
 
void SetSpecialPhysicsCuts () override
 
void FinishPrimary () override
 
void FinishRun () override
 
void BeginPrimary () override
 
void PostTrack () override
 
void PreTrack () override
 
void BeginEvent () override
 
void CopyClones (TClonesArray *cl1, TClonesArray *cl2, Int_t offset) override
 
- Public Member Functions inherited from ISTLPointContainer
virtual void UpdatePointTrackIndices (const std::map< Int_t, Int_t > &indexMap)=0
 Update track indices in point collection after track filtering.
 
virtual ~ISTLPointContainer ()=default
 

Private Member Functions

 MTCDetector (const MTCDetector &)=delete
 local SiPM channel position
 
MTCDetectoroperator= (const MTCDetector &)=delete
 

Private Attributes

Double_t fWidth
 
Double_t fHeight
 
Double_t fSciFiActiveX
 
Double_t fSciFiActiveY
 
Double_t fSciFiBendingAngle
 
Double_t fIronThick
 
Double_t fSciFiThick
 
Double_t fScintThick
 
Double_t fScintCellSize
 
Int_t fLayers
 
Double_t fZCenter
 
Double_t fFieldY
 
Double_t fZEpoxyMat
 
Double_t fiberMatThick = 0.135
 
Double_t fFiberLength
 
Double_t fFiberPitch = 0.025
 
Double_t lowerIronThick = 0.3
 
Double_t airGap = 0.1
 
Double_t upperIronThick = 0.3
 
Double_t zLowerIronInt = -3.5 / 10
 
Double_t zFiberMat1 = -1.325 / 10
 
Double_t zAirGap = -0.15 / 10
 
Double_t zFiberMat2 = 1.025 / 10
 
Double_t zUpperIronInt = 3.2 / 10
 
Double_t fFiberRadius = 0.01125
 
Int_t numFiberLayers = 6
 
Int_t fNSiPMChan
 
Int_t fChannelAggregated
 
Int_t fNSiPMs = 1
 
Int_t fNMats = 1
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > fibresSiPM_U
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > siPMFibres_U
 mapping of fibres to SiPM channels
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > fibresSiPM_V
 inverse mapping
 
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > siPMFibres_V
 mapping of fibres to SiPM channels
 
std::map< Int_t, float > SiPMPos_U
 inverse mapping
 
std::map< Int_t, float > SiPMPos_V
 

Static Private Attributes

static constexpr Int_t kMaxChannelsPerSiPM = 1000
 

Additional Inherited Members

- Protected Attributes inherited from SHiP::Detector< MTCDetPoint >
Int_t fEventID
 
Int_t fTrackID
 event index
 
Int_t fVolumeID
 track index
 
TLorentzVector fPos
 volume id
 
TLorentzVector fMom
 position at entrance
 
Double_t fTime
 momentum at entrance
 
Double_t fLength
 time
 
Double_t fELoss
 length
 
std::vector< MTCDetPoint > * fDetPoints
 energy loss
 
TGeoVolume * fDetector
 

Detailed Description

Definition at line 21 of file MTCDetector.h.

Constructor & Destructor Documentation

◆ MTCDetector() [1/3]

MTCDetector::MTCDetector ( const char *  name,
Bool_t  Active,
const char *  Title = "",
Int_t  DetId = 0 
)

Definition at line 144 of file MTCDetector.cxx.

146 : Detector(name, Active, kMTC) {}
@ kMTC

◆ MTCDetector() [2/3]

Definition at line 142 of file MTCDetector.cxx.

142: Detector("MTC", kTRUE, kMTC) {}

◆ MTCDetector() [3/3]

MTCDetector::MTCDetector ( const MTCDetector )
privatedelete

local SiPM channel position

Member Function Documentation

◆ ConstructGeometry()

void MTCDetector::ConstructGeometry ( )
overridevirtual

Create the detector geometry

Implements SHiP::Detector< MTCDetPoint >.

Definition at line 316 of file MTCDetector.cxx.

316 {
317 // Initialize media (using FairROOT's interface)
318 ShipGeo::InitMedium("SciFiMat");
319 ShipGeo::InitMedium("Epoxy");
320 ShipGeo::InitMedium("air");
321 TGeoMedium* air = gGeoManager->GetMedium("air");
322 TGeoMedium* ironMed = gGeoManager->GetMedium("iron");
323 // For the scintillator, you may use the same medium as SciFiMat or another if
324 // defined.
325 TGeoMedium* scintMed = gGeoManager->GetMedium("SciFiMat");
326 ShipGeo::InitMedium("silicon");
327
328 // Define the module spacing based on three sublayers:
329 // fIronThick (outer iron), fSciFiThick (SciFi module/fiber module),
330 // fScintThick (scintillator)
331 Double_t moduleSpacing = fIronThick + fSciFiThick + fScintThick;
332 Double_t totalLength = fLayers * moduleSpacing;
333
334 // --- Create an envelope volume for the detector (green, semi-transparent)
335 // ---
336 auto envBox =
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);
341
342 // --- Outer Iron Layer (gray) ---
343 auto ironBox =
344 new TGeoBBox("MTC_iron", fWidth / 2, fHeight / 2, fIronThick / 2);
345 auto ironVol = new TGeoVolume("MTC_iron", ironBox, ironMed);
346 ironVol->SetLineColor(kGray + 1);
347 ironVol->SetTransparency(20);
348 // Enable the field in the iron volume
349 if (fFieldY != 0) ironVol->SetField(new TGeoUniformMagField(0, fFieldY, 0));
350
351 // --- Assemble the layers into the envelope ---
352 TGeoVolumeAssembly* sensitiveModule = new TGeoVolumeAssembly("MTC_layer");
353 // Define a layer for the SciFi module
354 CreateSciFiModule("MTC", sensitiveModule, fWidth, fHeight, fSciFiThick, 1);
355 CreateScintModule("MTC", sensitiveModule, fSciFiThick / 2 + fScintThick / 2,
356 fWidth, fHeight, fScintThick, fScintCellSize,
357 fScintCellSize, scintMed, kAzure + 7, 30, 1);
358
359 for (Int_t i = 0; i < fLayers; i++) {
360 // Compute the center position (z) for the current module
361 Double_t zPos = -totalLength / 2 + i * moduleSpacing;
362
363 // Place the Outer Iron layer (shifted down by half the SciFi+scint
364 // thickness)
365 envVol->AddNode(ironVol, i,
366 new TGeoTranslation(0, 0, zPos + fIronThick / 2));
367 // Place the sensitive module (SciFi + Scintillator) at the correct z
368 // position
369 envVol->AddNode(
370 sensitiveModule, i,
371 new TGeoTranslation(0, 0, zPos + fIronThick + fSciFiThick / 2));
372 }
373
374 // Finally, add the envelope to the top volume with the global z offset
375 // fZCenter
376 gGeoManager->GetTopVolume()->AddNode(envVol, 1,
377 new TGeoTranslation(0, 0, fZCenter));
378}
Int_t InitMedium(const char *name)
Definition: ShipGeoUtil.h:20

◆ CreateSciFiModule()

void MTCDetector::CreateSciFiModule ( const char *  name,
TGeoVolumeAssembly *  modMotherVol,
Double_t  width,
Double_t  height,
Double_t  thickness,
Int_t  LayerId 
)
virtual

Definition at line 202 of file MTCDetector.cxx.

205 {
206 // --- Lower Internal Iron ---
207 TGeoBBox* lowerIronBox = new TGeoBBox(Form("%s_lowerIron", name), width / 2,
208 height / 2, lowerIronThick / 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,
214 new TGeoTranslation(0, 0, zLowerIronInt));
215
216 // --- Lower Epoxy matrix (replaces SciFiMat layer) ---
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,
221 height / 2, fiberMatThick / 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));
229
230 // --- Upper Epoxy matrix (replaces SciFiMat layer) ---
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,
235 height / 2, fiberMatThick / 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));
243
244 // --- Upper Internal Iron ---
245 TGeoBBox* upperIronBox = new TGeoBBox(Form("%s_upperIron", name), width / 2,
246 height / 2, upperIronThick / 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,
252 new TGeoTranslation(0, 0, zUpperIronInt));
253
254 // -----------------------------
255 // Now build the fibers inside each Epoxy block:
256 // Common fiber parameters (cm)
257 Double_t layerThick = fiberMatThick / numFiberLayers;
258 fFiberLength = fSciFiActiveY / cos(fSciFiBendingAngle * TMath::DegToRad()) -
259 2 * fFiberRadius * sin(fSciFiBendingAngle * TMath::DegToRad());
260 LOG(info) << "Fiber length set to " << fFiberLength << " cm";
261 Int_t fNumFibers = static_cast<Int_t>(fSciFiActiveX / fFiberPitch);
262
263 // --- Define the SciFi fiber volume ---
264 TGeoTube* fiberTube =
265 new TGeoTube("FiberTube", 0, fFiberRadius, fFiberLength / 2);
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);
272
273 // --- Rotations for U/V fibers ---
274 TGeoRotation* rotU = new TGeoRotation();
275 rotU->RotateY(fSciFiBendingAngle);
276 rotU->RotateX(90.);
277 TGeoRotation* rotV = new TGeoRotation();
278 rotV->RotateY(-fSciFiBendingAngle);
279 rotV->RotateX(90.);
280
281 // --- Place U-fibers inside lower Epoxy ---
282 for (int layer = 0; layer < numFiberLayers; ++layer) {
283 Double_t z0 = -fiberMatThick / 2 + (layer + 0.5) * (layerThick);
284 for (int j = 0; j < fNumFibers; ++j) {
285 Double_t x0 = -fSciFiActiveX / 2 + (j + 0.5) * fFiberPitch;
286 if (layer % 2 == 1) {
287 if (j == fNumFibers - 1) {
288 continue; // Skip the last layer for odd layers
289 }
290 x0 += fFiberPitch / 2;
291 }
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);
295 }
296 }
297
298 // --- Place V-fibers inside upper Epoxy ---
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) {
302 Double_t x0 = -fSciFiActiveX / 2 + (j + 0.5) * fFiberPitch;
303 if (layer % 2 == 1) {
304 if (j == fNumFibers - 1) {
305 continue; // Skip the last layer for odd layers
306 }
307 x0 += fFiberPitch / 2;
308 }
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);
312 }
313 }
314}
Double_t fiberMatThick
Definition: MTCDetector.h:86
Double_t fSciFiActiveX
Definition: MTCDetector.h:75
Double_t fFiberPitch
Definition: MTCDetector.h:88

◆ CreateScintModule()

void MTCDetector::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

Definition at line 170 of file MTCDetector.cxx.

176 {
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,
184 thickness / 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);
191
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));
198 }
199 }
200}

◆ Get_NSiPMChan()

Int_t MTCDetector::Get_NSiPMChan ( ) const
inline

Definition at line 67 of file MTCDetector.h.

67{ return fNSiPMChan; }

◆ Get_SciFiActiveX()

Float_t MTCDetector::Get_SciFiActiveX ( ) const
inline

Definition at line 68 of file MTCDetector.h.

68{ return fSciFiActiveX; }

◆ GetFibresMapU()

std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > MTCDetector::GetFibresMapU ( )
inline

Definition at line 56 of file MTCDetector.h.

56 {
57 return siPMFibres_U;
58 }

◆ GetFibresMapV()

std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > MTCDetector::GetFibresMapV ( )
inline

Definition at line 62 of file MTCDetector.h.

62 {
63 return siPMFibres_V;
64 }

◆ GetLocalPos()

TVector3 MTCDetector::GetLocalPos ( Int_t  fDetectorID,
TVector3 *  glob 
)

Transform global position to local position in plane

Definition at line 565 of file MTCDetector.cxx.

565 {
566 Int_t station_number = static_cast<int>(fDetectorID / 1e6) % 100;
567 Int_t plane_type = static_cast<int>(fDetectorID / 1e5) %
568 10; // 0 for horizontal, 1 for vertical
569
570 TString sID, stationID;
571 sID.Form("%i", fDetectorID);
572 stationID.Form("%i", station_number);
573 // Basic hierarchy:
574 // /cave/MTC_1/MTC_layer_1/MTC_sciFi_mother_1/MTC_sciFi_epoxyMat_U_1/FiberVol_101010187
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();
578 nav->cd(path);
579 Double_t aglob[3];
580 Double_t aloc[3];
581 glob->GetXYZ(aglob);
582 nav->MasterToLocal(aglob, aloc);
583 return TVector3(aloc[0], aloc[1], aloc[2]);
584}

◆ GetPosition()

void MTCDetector::GetPosition ( Int_t  fDetectorID,
TVector3 &  vLeft,
TVector3 &  vRight 
)

Get position of single fibre in global coordinate system

Definition at line 517 of file MTCDetector.cxx.

517 {
518 /*
519 Example of fiberID: 123051820, where:
520 - 1: MTC unique ID
521 - 23: layer number
522 - 0: station type (0 for +5 degrees, 1 for -5 degrees, 2 for scint plane)
523 - 5: z-layer number (0-5)
524 - 1820: local fibre ID within the station
525 Example of SiPM global channel (what is seen in the output file): 123001123,
526 where:
527 - 1: MTC unique ID
528 - 23: layer number
529 - 0: station type (0 for +5 degrees, 1 for -5 degrees)
530 - 0: mat number (only 0 by June 2025)
531 - 1: SiPM number (automatically assigned based on fibre aggregation
532 settings)
533 - 123: number of the SiPM channel (0-N). The channel number depends on the
534 fibre aggregation setting.
535 */
536
537 Int_t station_number = static_cast<int>(fDetectorID / 1e6) % 100;
538 Int_t plane_type = static_cast<int>(fDetectorID / 1e5) %
539 10; // 0 for horizontal, 1 for vertical
540
541 TString sID, stationID;
542 sID.Form("%i", fDetectorID);
543 stationID.Form("%i", station_number);
544 // Basic hierarchy:
545 // /cave/MTC_1/MTC_layer_1/MTC_sciFi_mother_1/MTC_sciFi_epoxyMat_U_1/FiberVol_101010187
546 TString path =
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");
550 path += sID(4, 5);
551 TGeoNavigator* nav = gGeoManager->GetCurrentNavigator();
552 nav->cd(path);
553 TGeoNode* W = nav->GetCurrentNode();
554 TGeoBBox* S = dynamic_cast<TGeoBBox*>(W->GetVolume()->GetShape());
555
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]);
563}
Definition: diagrams_a.h:3
Definition: diagrams_b.h:4

◆ GetSiPMmapU()

std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > MTCDetector::GetSiPMmapU ( )
inline

Definition at line 53 of file MTCDetector.h.

53 {
54 return fibresSiPM_U;
55 }

◆ GetSiPMmapV()

std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > MTCDetector::GetSiPMmapV ( )
inline

Definition at line 59 of file MTCDetector.h.

59 {
60 return fibresSiPM_V;
61 }

◆ GetSiPMPos_U()

std::map< Int_t, float > MTCDetector::GetSiPMPos_U ( )
inline

Definition at line 65 of file MTCDetector.h.

65{ return SiPMPos_U; }

◆ GetSiPMPos_V()

std::map< Int_t, float > MTCDetector::GetSiPMPos_V ( )
inline

Definition at line 66 of file MTCDetector.h.

66{ return SiPMPos_V; }

◆ GetSiPMPosition()

void MTCDetector::GetSiPMPosition ( Int_t  SiPMChan,
TVector3 &  A,
TVector3 &  B 
)

mean position of fibre2 associated with SiPM channel

Definition at line 586 of file MTCDetector.cxx.

586 {
587 /* STMRFFF
588 Example of fiberID: 123051820, where:
589 - 1: MTC unique ID
590 - 23: layer number
591 - 0: station type (0 for +5 degrees, 1 for -5 degrees, 2 for scint
592 plane)
593 - 5: z-layer number (0-5)
594 - 1820: local fibre ID within the station
595 Example of SiPM global channel (what is seen in the output file):
596 123001123, where:
597 - 1: MTC unique ID
598 - 23: layer number
599 - 0: station type (0 for +5 degrees, 1 for -5 degrees)
600 - 0: mat number (only 0 by June 2025)
601 - 1: SiPM number (automatically assigned based on fibre aggregation
602 settings)
603 - 123: number of the SiPM channel (0-N). The channel number depends on
604 the fibre aggregation setting.
605 */
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) %
609 10; // 0 for horizontal, 1 for vertical
610 Float_t locPosition;
611 locPosition =
612 (plane_type == 0 ? SiPMPos_U
613 : SiPMPos_V)[locNumber]; // local position in U/V plane
614 TString stationID;
615 stationID.Form("%i", station_number);
616
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;
624 loc[1] = -fFiberLength / 2;
625 loc[2] = 7.47;
626 nav->cd(path);
627 nav->LocalToMaster(loc, glob);
628 A.SetXYZ(glob[0], glob[1], glob[2]);
629 loc[0] = locPosition;
630 loc[1] = fFiberLength / 2;
631 loc[2] = 7.47; // hardcoded for now, for some reason required to get the
632 // correct local position
633 nav->LocalToMaster(loc, glob);
634 B.SetXYZ(glob[0], glob[1], glob[2]);
635}
Double_t fFiberLength
Definition: MTCDetector.h:87

◆ operator=()

MTCDetector & MTCDetector::operator= ( const MTCDetector )
privatedelete

◆ ProcessHits()

Bool_t MTCDetector::ProcessHits ( FairVolume *  vol = 0)
override

This method is called from the MC stepping

Definition at line 380 of file MTCDetector.cxx.

380 {
382 // Set parameters at entrance of volume. Reset ELoss.
383 if (gMC->IsTrackEntering()) {
384 fELoss = 0.;
385 fTime = gMC->TrackTime() * 1.0e09;
386 fLength = gMC->TrackLength();
387 gMC->TrackPosition(fPos);
388 gMC->TrackMomentum(fMom);
389 TGeoNavigator* nav = gGeoManager->GetCurrentNavigator();
390 Int_t vol_local_id = nav->GetCurrentNode()->GetNumber() %
391 1000000; // Local ID within the mat or scint.
392 Int_t layer_id = nav->GetMother(3)->GetNumber(); // Get layer ID.
393 fVolumeID = 100000000 + layer_id * 1000000 +
394 vol_local_id; // 1e8 + layer_id * 1e6 + fibre_local_id;
395 }
396 // Sum energy loss for all steps in the active volume
397 fELoss += gMC->Edep();
398
399 // Create vetoPoint when exiting active volume
400 if (gMC->IsTrackExiting() || gMC->IsTrackStop() ||
401 gMC->IsTrackDisappeared()) {
402 if (fELoss == 0.) {
403 return kFALSE;
404 } // if you do not want hits with zero eloss
405
406 TParticle* p = gMC->GetStack()->GetCurrentTrack();
407 fTrackID = gMC->GetStack()->GetCurrentTrackNumber();
408 Int_t pdgCode = p->GetPdgCode();
409 TLorentzVector Pos;
410 gMC->TrackPosition(Pos);
411 TLorentzVector Mom;
412 gMC->TrackMomentum(Mom);
413 Double_t x, y, z;
414 if (fVolumeID / 100000 == 3) {
415 x = (fPos.X() + Pos.X()) / 2.;
416 y = (fPos.Y() + Pos.Y()) / 2.;
417 z = (fPos.Z() + Pos.Z()) / 2.;
418 } else {
419 x = fPos.X();
420 y = fPos.Y();
421 z = (fPos.Z() + Pos.Z()) / 2.;
422 }
423
424 AddHit(fTrackID, fVolumeID, TVector3(x, y, z),
425 TVector3(fMom.Px(), fMom.Py(), fMom.Pz()), // entrance momentum
426 fTime, fLength, fELoss, pdgCode);
427 // hit->Print();
428 ShipStack* stack = dynamic_cast<ShipStack*>(gMC->GetStack());
429 stack->AddPoint(kMTC);
430 }
431 return kTRUE;
432}
Int_t fTrackID
event index
Definition: Detector.h:85
TLorentzVector fPos
volume id
Definition: Detector.h:87
MTCDetPoint * AddHit(Args &&... args)
Definition: Detector.h:38
TLorentzVector fMom
position at entrance
Definition: Detector.h:88
ROOT p
Definition: makeDecay.py:76

◆ SetMTCParameters()

void MTCDetector::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 
)

Definition at line 148 of file MTCDetector.cxx.

153 {
154 fWidth = width;
155 fHeight = height;
156 fSciFiBendingAngle = fiber_tilt_angle;
157 fIronThick = iron_thickness;
158 fSciFiThick = scifi_thickness;
159 fChannelAggregated = num_of_agg_channels;
160 fScintCellSize = scint_cell_size;
161 fScintThick = scint_thickness;
162 fLayers = number_of_layers;
163 fZCenter = z_position;
164 fFieldY = field_strength;
165 fSciFiActiveX = fWidth - fWidth * tan(fSciFiBendingAngle * TMath::DegToRad());
166 fSciFiActiveY = fHeight;
167}

◆ SiPMmapping()

void MTCDetector::SiPMmapping ( )

Definition at line 637 of file MTCDetector.cxx.

637 {
638 // check if containers are already filled
639 if (!fibresSiPM_U.empty() || !fibresSiPM_V.empty() || !SiPMPos_U.empty() ||
640 !SiPMPos_V.empty()) {
641 LOG(warning) << "SiPM mapping already done, skipping.";
642 return;
643 }
644 Float_t fibresRadius = -1;
645 Float_t dSiPM = -1;
646 TGeoNode* vol;
647 TGeoNode* fibre;
648 SiPMOverlap();
649 // Loop over both U and V planes
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);
654 if (!sipm) continue;
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();
662 ifibre++) {
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();
668 }
669 Int_t fID =
670 fibre->GetNumber() % 1000000 +
671 imat * 1e4; // local fibre number, global fibre number = SO+fID
672 TVector3 Atop, Bbot;
673 GetPosition(fibre->GetNumber(), Atop, Bbot);
674 Float_t a = Bbot[0];
675
676 // check for overlap with any of the SiPM channels in the same mat
677 for (Int_t nChan = 0; nChan < Nodes->GetEntriesFast();
678 nChan++) { // 7 SiPMs total times 128 channels
679 vol = static_cast<TGeoNode*>(Nodes->At(nChan));
680 Int_t N = vol->GetNumber();
681 Float_t xcentre = vol->GetMatrix()->GetTranslation()[0];
682 if (dSiPM < 0) {
683 TGeoBBox* B = dynamic_cast<TGeoBBox*>(vol->GetVolume()->GetShape());
684 dSiPM = B->GetDX();
685 }
686
687 if (TMath::Abs(xcentre - a) > 3 * dSiPM / 2) {
688 continue;
689 } // no need to check further
690 Float_t W = area(a, fibresRadius, xcentre - dSiPM, xcentre + dSiPM);
691 if (W < 0) {
692 continue;
693 }
694 std::array<float, 2> Wa;
695 Wa[0] = W;
696 Wa[1] = a;
697
698 if (sipm_vol == std::string("SiPMmapVolU")) {
699 fibresSiPM_U[N][fID] = Wa;
700 } else {
701 fibresSiPM_V[N][fID] = Wa;
702 }
703 }
704 }
705 }
706 // calculate also local SiPM positions based on fibre positions and their
707 // fraction probably an overkill, maximum difference between weighted
708 // average and central position < 6 micron.
709 if (sipm_vol == std::string("SiPMmapVolU")) {
710 for (auto [N, it] : fibresSiPM_U) {
711 Float_t m = 0;
712 Float_t w = 0;
713 for (auto [current_fibre, Wa] : it) {
714 m += Wa[0] * Wa[1];
715 w += Wa[0];
716 }
717 SiPMPos_U[N] = m / w;
718 }
719 // make inverse mapping, which fibre is associated to which SiPMs
720 for (auto [N, it] : fibresSiPM_U) {
721 for (auto [nfibre, Wa] : it) {
722 siPMFibres_U[nfibre][N] = Wa;
723 }
724 }
725 } else if (sipm_vol == std::string("SiPMmapVolV")) {
726 for (auto [N, it] : fibresSiPM_V) {
727 Float_t m = 0;
728 Float_t w = 0;
729 for (auto [current_fibre, Wa] : it) {
730 m += Wa[0] * Wa[1];
731 w += Wa[0];
732 }
733 SiPMPos_V[N] = m / w;
734 }
735 // make inverse mapping, which fibre is associated to which SiPMs
736 for (auto [N, it] : fibresSiPM_V) {
737 for (auto [nfibre, Wa] : it) {
738 siPMFibres_V[nfibre][N] = Wa;
739 }
740 }
741 }
742 }
743}
Double_t m
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > siPMFibres_V
mapping of fibres to SiPM channels
Definition: MTCDetector.h:114
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > fibresSiPM_V
inverse mapping
Definition: MTCDetector.h:112
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > fibresSiPM_U
Definition: MTCDetector.h:108
std::map< Int_t, float > SiPMPos_U
inverse mapping
Definition: MTCDetector.h:115
std::map< Int_t, float > SiPMPos_V
Definition: MTCDetector.h:115
std::map< Int_t, std::map< Int_t, std::array< float, 2 > > > siPMFibres_U
mapping of fibres to SiPM channels
Definition: MTCDetector.h:110
void GetPosition(Int_t fDetectorID, TVector3 &vLeft, TVector3 &vRight)

◆ SiPMOverlap()

void MTCDetector::SiPMOverlap ( )
virtual

Definition at line 434 of file MTCDetector.cxx.

434 {
435 if (gGeoManager->FindVolumeFast("SiPMmapVolU") ||
436 gGeoManager->FindVolumeFast("SiPMmapVolV")) {
437 return;
438 }
439 Double_t fLengthScifiMat = fSciFiActiveY;
440 Double_t fWidthChannel = fFiberPitch * fChannelAggregated;
441 fNSiPMChan = std::ceil(fWidth / fWidthChannel);
442 if (fNSiPMChan > kMaxChannelsPerSiPM) {
443 LOG(warn) << "Number of SiPM channels (" << fNSiPMChan
444 << ") exceeds maximum per SiPM (" << kMaxChannelsPerSiPM
445 << "), redistributing across multiple SiPMs";
446
447 fNSiPMs = static_cast<int>(
448 std::ceil(static_cast<double>(fNSiPMChan) / kMaxChannelsPerSiPM));
449
450 LOG(info) << "Increasing number of SiPMs up to " << fNSiPMs;
451
452 // define redistribution of channels among SiPMs
453 fNSiPMChan =
454 static_cast<int>(std::ceil(fNSiPMChan / static_cast<float>(fNSiPMs)));
455
456 LOG(info) << "New fNSiPMChan = " << fNSiPMChan;
457 }
458 Double_t fEdge = (fWidth - fNSiPMs * fNSiPMChan * fWidthChannel) / 2;
459 Double_t firstChannelX = -fWidth / 2;
460
461 LOG(info) << "SiPM Overlap parameters:\n"
462 << " fLengthScifiMat = " << fLengthScifiMat << " cm\n"
463 << " fWidthChannel = " << fWidthChannel << " cm\n"
464 << " fFiberPitch = " << fFiberPitch << " cm\n"
465 << " fChannelAggregated = " << fChannelAggregated << "\n"
466 << " fNSiPMChan = " << fNSiPMChan << "\n"
467 << " fNSiPMs = " << fNSiPMs << "\n"
468 << " fNMats = " << fNMats << "\n"
469 << " fEdge = " << fEdge << " cm\n"
470 << " firstChannelX = " << firstChannelX << " cm";
471 // Contains all plane SiPMs, defined for horizontal fiber plane
472 // To obtain SiPM map for vertical fiber plane rotate by 90 degrees around Z
473 TGeoVolumeAssembly* SiPMmapVolU = new TGeoVolumeAssembly("SiPMmapVolU");
474 TGeoVolumeAssembly* SiPMmapVolV = new TGeoVolumeAssembly("SiPMmapVolV");
475
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"));
480 /*
481 Example of fiberID: 123051820, where:
482 - 1: MTC unique ID
483 - 23: layer number
484 - 0: station type (0 for +5 degrees, 1 for -5 degrees, 2 for scint plane)
485 - 5: z-layer number (0-5)
486 - 1820: local fibre ID within the station
487 Example of SiPM global channel (what is seen in the output file): 123001123,
488 where:
489 - 1: MTC unique ID
490 - 23: layer number
491 - 0: station type (0 for +5 degrees, 1 for -5 degrees)
492 - 0: mat number (only 0 by June 2025)
493 - 1: SiPM number (automatically assigned based on fibre aggregation
494 settings)
495 - 123: number of the SiPM channel (0-N). The channel number depends on the
496 fibre aggregation setting.
497 */
498
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++) {
503 // +5 degrees
504 SiPMmapVolU->AddNode(
505 ChannelVol, 100000 * 0 + imat * 10000 + isipms * 1000 + ichannel,
506 new TGeoTranslation(pos, 0, 0));
507 // -5 degrees
508 SiPMmapVolV->AddNode(
509 ChannelVol, 100000 * 1 + imat * 10000 + isipms * 1000 + ichannel,
510 new TGeoTranslation(-pos, 0, 0));
511 pos += fWidthChannel;
512 }
513 }
514 }
515}
Double_t fWidth
Definition: MTCDetector.h:73
Int_t fNSiPMs
Definition: MTCDetector.h:103
Int_t fNSiPMChan
Definition: MTCDetector.h:101
Int_t fNMats
Definition: MTCDetector.h:106

Member Data Documentation

◆ airGap

Double_t MTCDetector::airGap = 0.1
private

Definition at line 92 of file MTCDetector.h.

◆ fChannelAggregated

Int_t MTCDetector::fChannelAggregated
private

Definition at line 102 of file MTCDetector.h.

◆ fFiberLength

Double_t MTCDetector::fFiberLength
private

Definition at line 87 of file MTCDetector.h.

◆ fFiberPitch

Double_t MTCDetector::fFiberPitch = 0.025
private

Definition at line 88 of file MTCDetector.h.

◆ fFiberRadius

Double_t MTCDetector::fFiberRadius = 0.01125
private

Definition at line 99 of file MTCDetector.h.

◆ fFieldY

Double_t MTCDetector::fFieldY
private

Definition at line 84 of file MTCDetector.h.

◆ fHeight

Double_t MTCDetector::fHeight
private

Definition at line 74 of file MTCDetector.h.

◆ fiberMatThick

Double_t MTCDetector::fiberMatThick = 0.135
private

Definition at line 86 of file MTCDetector.h.

◆ fibresSiPM_U

std::map<Int_t, std::map<Int_t, std::array<float, 2> > > MTCDetector::fibresSiPM_U
private

Definition at line 108 of file MTCDetector.h.

◆ fibresSiPM_V

std::map<Int_t, std::map<Int_t, std::array<float, 2> > > MTCDetector::fibresSiPM_V
private

inverse mapping

Definition at line 112 of file MTCDetector.h.

◆ fIronThick

Double_t MTCDetector::fIronThick
private

Definition at line 78 of file MTCDetector.h.

◆ fLayers

Int_t MTCDetector::fLayers
private

Definition at line 82 of file MTCDetector.h.

◆ fNMats

Int_t MTCDetector::fNMats = 1
private

Definition at line 106 of file MTCDetector.h.

◆ fNSiPMChan

Int_t MTCDetector::fNSiPMChan
private

Definition at line 101 of file MTCDetector.h.

◆ fNSiPMs

Int_t MTCDetector::fNSiPMs = 1
private

Definition at line 103 of file MTCDetector.h.

◆ fSciFiActiveX

Double_t MTCDetector::fSciFiActiveX
private

Definition at line 75 of file MTCDetector.h.

◆ fSciFiActiveY

Double_t MTCDetector::fSciFiActiveY
private

Definition at line 76 of file MTCDetector.h.

◆ fSciFiBendingAngle

Double_t MTCDetector::fSciFiBendingAngle
private

Definition at line 77 of file MTCDetector.h.

◆ fSciFiThick

Double_t MTCDetector::fSciFiThick
private

Definition at line 79 of file MTCDetector.h.

◆ fScintCellSize

Double_t MTCDetector::fScintCellSize
private

Definition at line 81 of file MTCDetector.h.

◆ fScintThick

Double_t MTCDetector::fScintThick
private

Definition at line 80 of file MTCDetector.h.

◆ fWidth

Double_t MTCDetector::fWidth
private

Definition at line 73 of file MTCDetector.h.

◆ fZCenter

Double_t MTCDetector::fZCenter
private

Definition at line 83 of file MTCDetector.h.

◆ fZEpoxyMat

Double_t MTCDetector::fZEpoxyMat
private

Definition at line 85 of file MTCDetector.h.

◆ kMaxChannelsPerSiPM

constexpr Int_t MTCDetector::kMaxChannelsPerSiPM = 1000
staticconstexprprivate

Definition at line 104 of file MTCDetector.h.

◆ lowerIronThick

Double_t MTCDetector::lowerIronThick = 0.3
private

Definition at line 91 of file MTCDetector.h.

◆ numFiberLayers

Int_t MTCDetector::numFiberLayers = 6
private

Definition at line 100 of file MTCDetector.h.

◆ siPMFibres_U

std::map<Int_t, std::map<Int_t, std::array<float, 2> > > MTCDetector::siPMFibres_U
private

mapping of fibres to SiPM channels

Definition at line 110 of file MTCDetector.h.

◆ siPMFibres_V

std::map<Int_t, std::map<Int_t, std::array<float, 2> > > MTCDetector::siPMFibres_V
private

mapping of fibres to SiPM channels

Definition at line 114 of file MTCDetector.h.

◆ SiPMPos_U

std::map<Int_t, float> MTCDetector::SiPMPos_U
private

inverse mapping

Definition at line 115 of file MTCDetector.h.

◆ SiPMPos_V

std::map<Int_t, float> MTCDetector::SiPMPos_V
private

Definition at line 115 of file MTCDetector.h.

◆ upperIronThick

Double_t MTCDetector::upperIronThick = 0.3
private

Definition at line 93 of file MTCDetector.h.

◆ zAirGap

Double_t MTCDetector::zAirGap = -0.15 / 10
private

Definition at line 96 of file MTCDetector.h.

◆ zFiberMat1

Double_t MTCDetector::zFiberMat1 = -1.325 / 10
private

Definition at line 95 of file MTCDetector.h.

◆ zFiberMat2

Double_t MTCDetector::zFiberMat2 = 1.025 / 10
private

Definition at line 97 of file MTCDetector.h.

◆ zLowerIronInt

Double_t MTCDetector::zLowerIronInt = -3.5 / 10
private

Definition at line 94 of file MTCDetector.h.

◆ zUpperIronInt

Double_t MTCDetector::zUpperIronInt = 3.2 / 10
private

Definition at line 98 of file MTCDetector.h.


The documentation for this class was generated from the following files: