Skip to content
Snippets Groups Projects

Draft: Add MVD v25a geometry macro generating 2 sensors as under construction for mCBM 2025

1 file
+ 431
0
Compare changes
  • Side-by-side
  • Inline
+ 431
0
/* Copyright (C) 2020 Institut fuer Kernphysik, Goethe-Universitaet Frankfurt
SPDX-License-Identifier: GPL-3.0-only
Authors: Phillip Klaus [committer] */
// 2024-11-27 - DE - Stripped down variant mMVD 2025 with 2 sensors back to back based on MVD v20c by Phillip Klaus
/*
* ROOT Macro to create the geometry of the Micro Vertex Detector
* of the CBM experiment at FAIR. It is used within the CbmRoot
* framework to simulate the detector response.
*
* The main output of this script is a .root file containing the
* the volumes of the detector. The media those volumes are
* filled with / made of are referenced in this script only by name
* and defined in a separate ASCII file named media.geo.
*
* For some components, their medium is a surrogate with equivalent
* material budget to simplify the design and speed-up simulation or
* because we depend on educated estimates regarding their material
* composition for the time being.
*/
/*
* Parameters defining the MVD
*/
// DE static const int numStations = 4;
static const int numStations = 1;
// all units are in cm
// Float_t quadrantBeamOffset[4] = {0.54, 0.54, 0.82, 1.04};
Float_t carrierClampOverlap = 0.0;
// Float_t heatsinkWidth[4] = {23.1, 31.1, 34.34, 37.7};
Float_t heatsinkHeight = 37.7;
// Heatsink actual thickness: 1.0cm
// The additional contributionof 0.7cm is a surrogate
// for FEBs incl. FR-4, copper, connectors:
Float_t heatsinkThickness = 1.0 + 0.7;
Float_t topPlateThickness = 1.0;
Float_t fpcWidth = 1.9;
Float_t fpcThickness = 0.0009;
Float_t glueThickness = 0.0008;
/* MIMOSIS dimensions
https://indico.gsi.de/contributionDisplay.py?contribId=8&sessionId=6&confId=4759
30.97 x 16.55 mm2 (of which the lower 3mm inactive) */
Float_t sensorDimensionsActive[3] = {3.097, 1.355, 0.005};
Float_t sensorDimensionsPassive[3] = {3.097, 0.300, 0.005};
// Formula for the carrier dimensions height ([1]):
// nrows * sensorDimensionsActive[1] + (nrows - 1) * sensorActiveOverlap +
// sensorDimensionsPassive[1] + fpcWidth + 0.1 eg. for nrows=2:
// 2*1.355-(2-1)*0.05+0.3+1.9+0.1
/* MIMOSIS-based tr (tracking) variant (general purpose tracking variant) */
Float_t stationPosition[4] = {4.0, 8.0, 12.0, 16.0};
// DE int sensorRows[4] = {4, 4, 7, 7};
int sensorRows[4] = {2, 4, 7, 7}; // only 2 sensors
// DE int sensorCols[4] = {2, 2, 4, 4};
int sensorCols[4] = {1, 2, 4, 4}; // only 1 sensor
Float_t heatsinkWidth[4] = {31.1, 31.1, 37.7, 37.7};
Float_t quadrantBeamOffset[4] = {0.54, 0.54, 1.04, 1.04};
// 0.5 - 0.005 - 2 * 0.0008 = 0.4934
// 0.5233 - 0.005 - 2 * 0.0008 = 0.5167
// DE Float_t carrierDimensions[4][3] = {{3.097, 1.355, 0.4934}, // 0.5 cm gap
//Float_t carrierDimensions[4][3] = {{3.097, 1.655, 0.4934}, // 0.5 cm gap
Float_t carrierDimensions[4][3] = {{3.097, 1.655, 0.5167}, // 0.5 cm gap
{7.19, 7.57, 0.038},
{13.39, 11.485, 0.038},
{13.39, 11.485, 0.038}};
// DE Float_t carrierDimensions[4][3] = {{7.19, 7.57, 0.038},
// DE {7.19, 7.57, 0.038},
// DE {13.39, 11.485, 0.038},
// DE {13.39, 11.485, 0.038}};
int carrierMaterials[4] = {1, 1, 1, 1}; // 0 = diamond, 1 = TPG
/* MIMOSIS-based vx (vertexing) variant (dedicated vertexing variant) */
/*
Float_t stationPosition[4] = {1.0, 6.0, 11.0, 16.0};
int sensorRows[4] = {2, 4, 7, 7};
int sensorCols[4] = {1, 2, 4, 4};
Float_t heatsinkWidth[4] = {23.1, 31.1, 37.7, 37.7};
Float_t quadrantBeamOffset[4] = {0.54, 0.54, 1.04, 1.04};
Float_t carrierDimensions[4][3] = {{4.10, 4.96, 0.015},
{7.19, 7.57, 0.038},
{13.39, 11.485, 0.038},
{13.39, 11.485, 0.038}};
int carrierMaterials[4] = {0, 1, 1, 1}; // 0 = diamond, 1 = TPG
*/
Float_t sensorActiveOverlap = 0.05;
Float_t sensorPitch = sensorDimensionsActive[1] - sensorActiveOverlap;
Float_t sensorSpacing = 0.0; // realistically: 0.01 (100um)
// if an artificially exploded view is desired, adjust this parameter:
Float_t explosion =
1.0; // set to 1. for no explosion, and 3. for a heavy explosion
/*
* Procedural code assemblying the MVD
*/
void Create_MVD_geometry_v25a_mcbm() {
TGeoVolume *top;
TGeoVolume *stations[numStations];
TGeoVolume *quadrant;
// DE TCanvas *c3D = new TCanvas("c3D", "MVD Layout", 1600, 1200);
TCanvas *c3D = new TCanvas("c3D", "MVD Layout", 800, 600);
TGeoManager *manager = new TGeoManager("Chamber Layout", "Chamber Layout");
TGeoMaterial *mat = new TGeoMaterial("vacuum", 0., 0., 0.);
TGeoMaterial *matAl = new TGeoMaterial("aluminium", 0., 0., 0.);
TGeoMaterial *matSilicon = new TGeoMaterial("silicon", 0, 0, 0);
TGeoMaterial *matGlue = new TGeoMaterial("MVD_glue", 0, 0, 0);
TGeoMaterial *matTPG = new TGeoMaterial("MVD_tpg", 0, 0, 0);
TGeoMaterial *matDiamond = new TGeoMaterial("MVD_cvd_diamond", 0, 0, 0);
TGeoMaterial *matFPC = new TGeoMaterial("MVD_fpc", 0, 0, 0);
TGeoMedium *vac = new TGeoMedium("vacuumMed", 0, mat);
TGeoMedium *Al = new TGeoMedium("AlMed", 2, matAl);
TGeoMedium *silicon = new TGeoMedium("siliconMed", 2, matSilicon);
TGeoMedium *glue = new TGeoMedium("glueMed", 2, matGlue);
TGeoMedium *tpg = new TGeoMedium("tpgMed", 2, matTPG);
TGeoMedium *diamond = new TGeoMedium("diamondMed", 2, matDiamond);
TGeoMedium *FPC = new TGeoMedium("FPCMed", 2, matFPC);
top = manager->MakeBox("Top", vac, 300., 300., 300.);
manager->SetTopVolume(top);
TGeoVolume *mvd = new TGeoVolumeAssembly("MVDscripted");
TGeoVolume *sensorActive = manager->MakeBox(
"sensorActive", silicon, sensorDimensionsActive[0] / 2,
sensorDimensionsActive[1] / 2, sensorDimensionsActive[2] / 2);
TGeoVolume *sensorPassive = manager->MakeBox(
"sensorPassive", silicon, sensorDimensionsPassive[0] / 2,
sensorDimensionsPassive[1] / 2, sensorDimensionsPassive[2] / 2);
TGeoVolume *sensorGlue = manager->MakeBox(
"sensorGlue", glue, sensorDimensionsActive[0] / 2,
(sensorDimensionsActive[1] + sensorDimensionsPassive[1]) / 2,
glueThickness / 2);
sensorActive->SetTransparency(0);
sensorActive->SetLineColor(kAzure + 3);
sensorPassive->SetTransparency(0);
sensorPassive->SetLineColor(kCyan + 1);
sensorGlue->SetTransparency(0);
sensorGlue->SetLineColor(kCyan - 10);
Float_t fpcGlueDimensions[2] = {sensorDimensionsActive[0],
sensorPitch - sensorActiveOverlap};
TGeoVolume *fpcGlue =
manager->MakeBox("fpcGlue", glue, fpcGlueDimensions[0] / 2,
fpcGlueDimensions[1] / 2, glueThickness / 2);
fpcGlue->SetTransparency(0);
fpcGlue->SetLineColor(kCyan - 10);
TGeoTranslation T;
TGeoRotation R;
TGeoCombiTrans *M;
char station_name[30], quadrant_name[30], carrier_name[30], heatsink_name[30],
heatsinkpart_name[30], cable_name[30];
int heatsinkpartno = 0, cablepartno = 0;
// --- Sensor Assembly
TGeoVolume *sensor = new TGeoVolumeAssembly("sensor");
// Glue
Float_t x_offset = -sensorDimensionsActive[0] / 2;
Float_t y_offset =
-(sensorDimensionsActive[1] + sensorDimensionsPassive[1]) / 2;
Float_t z_offset = glueThickness / 2;
T.SetTranslation(x_offset, y_offset, -z_offset);
R.SetAngles(0., 0., 0.);
M = new TGeoCombiTrans(T, R);
// DE sensor->AddNode(sensorGlue, 1, M);
// Active
x_offset = -sensorDimensionsActive[0] / 2;
y_offset = -sensorDimensionsActive[1] / 2;
z_offset = sensorDimensionsActive[2] / 2 + glueThickness;
T.SetTranslation(x_offset, y_offset, -z_offset);
M = new TGeoCombiTrans(T, R);
sensor->AddNode(sensorActive, 1, M);
// Passive
y_offset = -sensorDimensionsPassive[1] / 2 - sensorDimensionsActive[1];
T.SetTranslation(x_offset, y_offset, -z_offset);
M = new TGeoCombiTrans(T, R);
sensor->AddNode(sensorPassive, 1, M);
for (int i = 0; i < numStations; i++) {
// --- Station Assembly
cout << "Station " << i << endl;
sprintf(station_name, "station_S%i", i);
TGeoVolume *station = new TGeoVolumeAssembly(station_name);
// --- Quadrant Assembly
sprintf(quadrant_name, "quadrant_S%i", i);
quadrant = new TGeoVolumeAssembly(quadrant_name);
// --- Heatsink Assembly
sprintf(heatsink_name, "heatsink_S%i", i);
TGeoVolume *heatsink = new TGeoVolumeAssembly(heatsink_name);
// --- Carrier
sprintf(carrier_name, "carrier_S%i", i);
Float_t cd[3] = {carrierDimensions[i][0], carrierDimensions[i][1],
carrierDimensions[i][2]};
TGeoMedium *carrierMedium;
int carrierColor;
switch (carrierMaterials[i]) {
case 0:
carrierMedium = diamond;
carrierColor = kGray;
break;
case 1:
carrierMedium = tpg;
// DE carrierColor = kGray + 3;
carrierColor = kGray;
break;
default:
printf("Carrier material index not found: %i\n", carrierMaterials[i]);
exit(1);
}
TGeoVolume *carrier =
manager->MakeBox(carrier_name, carrierMedium, cd[0] / 2, cd[1] / 2, cd[2] / 2);
carrier->SetTransparency(0);
carrier->SetLineColor(carrierColor);
T.SetTranslation(-cd[0] / 2, -cd[1] / 2, 0);
R.SetAngles(0., 0., 0.);
M = new TGeoCombiTrans(T, R);
// DE quadrant->AddNode(carrier, 1, M);
// DE // --- Heatsink
// DE R.SetAngles(0., 0., 0.);
// DE // first part next to carrier
// DE sprintf(heatsinkpart_name, "heatsinkpart_%i", heatsinkpartno++);
// DE Float_t height_1 = heatsinkWidth[i] / 2 - cd[1] + carrierClampOverlap -
// DE quadrantBeamOffset[i];
// DE Float_t width_1 = heatsinkWidth[i] / 2 + quadrantBeamOffset[i];
// DE Float_t thickness = heatsinkThickness;
// DE TGeoVolume *hs_part1 = manager->MakeBox(heatsinkpart_name, Al, width_1 / 2.,
// DE height_1 / 2., thickness / 2.);
// DE hs_part1->SetTransparency(10);
// DE hs_part1->SetLineColor(kGray);
// DE T.SetTranslation(-width_1 / 2, -height_1 / 2 - cd[1] + carrierClampOverlap,
// DE 0);
// DE M = new TGeoCombiTrans(T, R);
// DE quadrant->AddNode(hs_part1, 1, M);
// DE // second part next to carrier
// DE sprintf(heatsinkpart_name, "heatsinkpart_%i", heatsinkpartno++);
// DE Float_t height_2 = heatsinkWidth[i] - height_1 - width_1;
// DE Float_t width_2 = heatsinkWidth[i] / 2 - cd[0] + carrierClampOverlap +
// DE quadrantBeamOffset[i];
// DE TGeoVolume *hs_part2 = manager->MakeBox(heatsinkpart_name, Al, width_2 / 2,
// DE height_2 / 2, thickness / 2);
// DE hs_part2->SetTransparency(10);
// DE hs_part2->SetLineColor(kGray);
// DE T.SetTranslation(-width_2 / 2 - cd[0] + carrierClampOverlap, -height_2 / 2,
// DE 0);
// DE M = new TGeoCombiTrans(T, R);
// DE quadrant->AddNode(hs_part2, 1, M);
// DE // element to fill top and bottom if needed
// DE sprintf(heatsinkpart_name, "heatsinkpart_%i", heatsinkpartno++);
// DE Float_t height = (heatsinkHeight - heatsinkWidth[i]) / 2;
// DE if (height > 0.1) {
// DE TGeoVolume *hs_part3 =
// DE manager->MakeBox(heatsinkpart_name, Al, heatsinkWidth[i] / 2,
// DE height / 2, heatsinkThickness / 2);
// DE hs_part3->SetTransparency(10);
// DE hs_part3->SetLineColor(kGray);
// DE T.SetTranslation(0, height / 2 + heatsinkWidth[i] / 2, 0);
// DE M = new TGeoCombiTrans(T, R);
// DE heatsink->AddNode(hs_part3, 1, M);
// DE T.SetTranslation(0, -(height / 2 + heatsinkWidth[i] / 2), 0);
// DE M = new TGeoCombiTrans(T, R);
// DE heatsink->AddNode(hs_part3, 2, M);
// DE T.SetTranslation(0, 0, 0);
// DE M = new TGeoCombiTrans(T, R);
// DE station->AddNode(heatsink, 1, M);
// DE }
// --- Sensors
cout << " # of sensors per quadrant: " << sensorCols[i] * sensorRows[i]
<< endl;
R.SetAngles(0., 0., 0.);
TGeoVolume *cable;
Float_t cableDimensions[2] = {0.0, 0.0};
for (int k = 0; k < sensorCols[i]; k++) {
if (k % 2 == 0) {
// Make new cable with correct dimensions
sprintf(cable_name, "cable_%i", cablepartno++);
cableDimensions[0] = cd[0] - sensorDimensionsActive[0] * k;
cableDimensions[1] = fpcWidth;
cable = manager->MakeBox(cable_name, FPC, cableDimensions[0] / 2,
cableDimensions[1] / 2, fpcThickness / 2);
cable->SetTransparency(0);
cable->SetLineColor(kSpring - 1);
}
for (int l = 0; l < sensorRows[i]; l++) {
// DE Float_t y_offset = -sensorPitch * l;
Float_t y_offset = 0;
Float_t z_offset = cd[2] / 2;
R.SetAngles(0., 0., 0.);
Float_t x_offset = -sensorDimensionsActive[0] * k;
if (l % 2 == 0) // front side
z_offset = -z_offset;
if (l % 2 == 1) // back side
{
R.SetAngles(0., 180., 180.);
x_offset -= sensorDimensionsActive[0];
}
T.SetTranslation(x_offset, y_offset, z_offset);
M = new TGeoCombiTrans(T, R);
quadrant->AddNode(sensor, k * sensorRows[i] + l, M);
// DE if (k % 2 == 0) {
// DE // add FPC and glue for the cable
// DE Float_t directional_z_offset = 0.0;
// DE directional_z_offset += glueThickness; // sensor glue
// DE directional_z_offset += sensorDimensionsActive[2]; // sensor
// DE directional_z_offset +=
// DE (fpcThickness + glueThickness) * (k / 2); // fpcAssembly pitch
// DE // fpcGlue
// DE Float_t fpcGlue_x_offset =
// DE -fpcGlueDimensions[0] / 2 - sensorDimensionsActive[0] * k;
// DE Float_t fpcGlue_y_offset = -fpcGlueDimensions[1] / 2 -
// DE sensorPitch * (l + 1) -
// DE sensorDimensionsPassive[1];
// DE Float_t fpcGlue_z_offset = z_offset;
// DE directional_z_offset += glueThickness / 2;
// DE if (l % 2 == 0) // front side
// DE fpcGlue_z_offset -= directional_z_offset;
// DE if (l % 2 == 1) // back side
// DE fpcGlue_z_offset += directional_z_offset;
// DE T.SetTranslation(fpcGlue_x_offset, fpcGlue_y_offset,
// DE fpcGlue_z_offset);
// DE R.SetAngles(0., 0., 0.);
// DE M = new TGeoCombiTrans(T, R);
// DE quadrant->AddNode(fpcGlue, 1, M);
// DE if (k != sensorCols[i] - 1) {
// DE T.SetTranslation(fpcGlue_x_offset - fpcGlueDimensions[0],
// DE fpcGlue_y_offset, fpcGlue_z_offset);
// DE R.SetAngles(0., 0., 0.);
// DE M = new TGeoCombiTrans(T, R);
// DE quadrant->AddNode(fpcGlue, 1, M);
// DE }
// DE // cable
// DE Float_t fpc_x_offset =
// DE -cableDimensions[0] / 2 - sensorDimensionsActive[0] * k;
// DE Float_t fpc_y_offset = -cableDimensions[1] / 2 -
// DE sensorPitch * (l + 1) -
// DE sensorDimensionsPassive[1];
// DE Float_t fpc_z_offset = z_offset;
// DE directional_z_offset += glueThickness / 2;
// DE directional_z_offset += fpcThickness / 2;
// DE if (l % 2 == 0) // front side
// DE fpc_z_offset -= directional_z_offset;
// DE if (l % 2 == 1) // back side
// DE fpc_z_offset += directional_z_offset;
// DE T.SetTranslation(fpc_x_offset, fpc_y_offset, fpc_z_offset);
// DE R.SetAngles(0., 0., 0.);
// DE M = new TGeoCombiTrans(T, R);
// DE quadrant->AddNode(cable, l + 1, M);
// DE }
}
}
for (int j = 0; j < 1; j++) { // only 1 quadrant
// DE for (int j = 0; j < 4; j++) {
cout << " Quadrant " << j << endl;
Float_t x_sign = (j == 0 || j == 3) ? 1. : -1.;
Float_t y_sign = (j == 0 || j == 1) ? -1. : 1.;
T.SetTranslation(0, 0, (0.5233+0.005) / 2);
// DE T.SetTranslation(x_sign * quadrantBeamOffset[i],
// DE y_sign * quadrantBeamOffset[i], 0);
R.SetAngles(0., 0., -90. * j);
M = new TGeoCombiTrans(T, R);
station->AddNode(quadrant, j, M);
}
// DE T.SetTranslation(0, 0, explosion * stationPosition[i]);
T.SetTranslation(0, 0, 0);
R.SetAngles(0., 0., 0.);
M = new TGeoCombiTrans(T, R);
mvd->AddNode(station, 1, M);
// DE station->Draw("ogl");
station->Draw("");
gPad->GetView()->RotateView(90, 180);
// DE char filename[30];
// DE sprintf(filename, "mvd.root.S%i.pdf", i);
// DE c3D->SaveAs(filename);
stations[i] = station;
}
// DE // Add top and bottom mounting plates
// DE double depth =
// DE stationPosition[numStations - 1] - stationPosition[0] + heatsinkThickness;
// DE TGeoVolume *top_bottom_plate = manager->MakeBox(
// DE "top_bottom_plate", Al, heatsinkWidth[numStations - 1] / 2,
// DE topPlateThickness / 2, depth / 2);
// DE top_bottom_plate->SetTransparency(10);
// DE top_bottom_plate->SetLineColor(kGray);
// DE T.SetTranslation(0, +heatsinkHeight / 2 + topPlateThickness / 2,
// DE depth / 2 + stationPosition[0] - heatsinkThickness / 2);
// DE M = new TGeoCombiTrans(T, R);
// DE mvd->AddNode(top_bottom_plate, 1, M);
// DE T.SetTranslation(0, -heatsinkHeight / 2 - topPlateThickness / 2,
// DE depth / 2 + stationPosition[0] - heatsinkThickness / 2);
// DE M = new TGeoCombiTrans(T, R);
// DE mvd->AddNode(top_bottom_plate, 2, M);
// Demonstration target:
// TGeoVolume *target = manager->MakeBox("target", silicon, 0.5, 0.5, 0.05);
// mvd->AddNode(target, 1);
top->AddNode(mvd, 1);
// Standard checks, to be executed at least before submitting a new geo
manager->CloseGeometry();
manager->CheckOverlaps(0.001, "s");
top->CheckOverlaps(0.001, "s");
top->FindOverlaps();
quadrant->CheckOverlaps(0.001, "s");
manager->CheckGeometryFull();
// done with standard checks
top->Export("mvd_v25a_mcbm.geo.root");
// Also add transformation matrix to place in space:
TGeoTranslation *mvd_trans = new TGeoTranslation("", 0., 0., 0);
TGeoRotation *mvd_rot = new TGeoRotation();
TGeoCombiTrans *mvd_combi_trans = new TGeoCombiTrans(*mvd_trans, *mvd_rot);
TFile *outfile = new TFile("mvd_v25a_mcbm.geo.root", "UPDATE");
mvd_combi_trans->Write();
outfile->Close();
// mvd->Draw("ogl");
// station->Draw("ogl");
// quadrant->Draw("ogl");
// quadrant->Draw("");
// quadrant->Raytrace();
// top->Draw("");
// gPad->GetView()->ShowAxis();
// top->Raytrace();
}
Loading