BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
create_rootgeom_HGND_run9.C
Go to the documentation of this file.
2#include "TFile.h"
3#include "TGeoManager.h"
4#include "TGeoMedium.h"
5#include "TGeoVolume.h"
6
7class FairGeoMedia;
8class FairGeoBuilder;
9
10// ===========================================================================
11// Detector geometry constants
12// ===========================================================================
13namespace NDetGeom
14{
15
16// Module grid: 1x1 (single detector element per layer)
17constexpr Int_t kNRows = 1;
18constexpr Int_t kNColumns = 1;
19constexpr Int_t kNLayers = 2;
21
22// --- Full sizes, cm (NOT half-sizes) -----------------------------------
23// TGeoBBox's constructor requires half-sizes -- that conversion is done
24// exactly once, at each TGeoBBox(...) call below, via the Half() helper.
25// Nowhere else in this file should a half-size ever appear.
26constexpr Double_t kScintSizeX = 4.0, kScintSizeY = 4.0, kScintSizeZ = 2.5; // scintillator cell
27constexpr Double_t kG10SizeX = kNColumns * kScintSizeX; // PCB, same footprint as the cell
29constexpr Double_t kG10SizeZ = 0.2;
30
31constexpr Double_t kEnvelopeMargin = 0.0001;
32
33// --- Layer positions, front-face-relative, cm ---------------------------
34// z = 0 is the front face of the first layer. Both layers are identical
35// (scintillator cell + PCB immediately behind it).
36constexpr Double_t kScintFrontZ[kNLayers] = {0.0, 10};
37
41
42// ROOT's TGeoBBox is always centered on its own local origin -- there is no
43// way around that. Half() converts a full size to the half-size the
44// constructor wants; FrontToLocalZ() converts a front-face-relative z
45// (0-based, always >= 0, the coordinate a physicist naturally writes down)
46// into a z relative to the envelope's own centered local origin (what
47// TGeoTranslation actually needs). Both conversions happen only inside
48// these two helpers -- nowhere else in the file.
49constexpr Double_t Half(Double_t fullSize)
50{
51 return fullSize / 2.0;
52}
53constexpr Double_t FrontToLocalZ(Double_t zFront)
54{
55 return zFront - Half(kEnvelopeSizeZ);
56}
57
58} // namespace NDetGeom
59
60// ===========================================================================
61// Media
62// ===========================================================================
67
68void DefineRequiredMedia(FairGeoMedia* geoMedia, FairGeoBuilder* geoBuild)
69{
70 auto loadMedium = [&](const char* name, TGeoMedium*& dest) {
71 FairGeoMedium* m = geoMedia->getMedium(name);
72 if (!m)
73 Fatal("DefineRequiredMedia", "FairMedium '%s' not found", name);
74 geoBuild->createMedium(m);
75 dest = gGeoManager->GetMedium(name);
76 if (!dest)
77 Fatal("DefineRequiredMedia", "Medium '%s' not found after creation", name);
78 };
79
80 loadMedium("vacuum", pMedVacuum);
81 loadMedium("air", pMedAir);
82 loadMedium("G10", pMedG10);
83 loadMedium("polystyrene", pMedScint); // scintillator
84}
85
86// ===========================================================================
87// Main geometry construction macro
88// ===========================================================================
89/**
90 * HGND Run9 geometry creation macro
91 * Two identical layers (scintillator cell + PCB),
92 * no absorber between them -- a bare test-stand / cosmic-test geometry.
93 *
94 * \param distToDetector Distance from target to the front face of detector, cm.
95 * \param yShift Vertical shift of the detector center, cm.
96 * \param rotYdeg Rotation of the detector around the Y axis, degrees.
97 * \param rotXdeg Rotation of the detector around the X axis, degrees.
98 * \param geoTag Optional short tag appended to the output geometry
99 */
100void create_rootgeom_HGND_run9(Double_t distToDetector = 699.7,
101 Double_t yShift = 0.0,
102 Double_t rotYdeg = -10.0,
103 Double_t rotXdeg = 0.0,
104 const char* geoTag = "")
105{
106 using namespace NDetGeom;
107
108 bmnloadlibs(); // load libraries
109
110 TString workDir = gSystem->Getenv("VMCWORKDIR");
111 const TString geoDetectorName = "HGND";
112
113 TString geoFileName = Form("%s/geometry/%s_dist%.3fcm_yshift%.3fcm_rotY%.2fdeg_rotX%.2fdeg%s%s.root",
114 workDir.Data(), geoDetectorName.Data(), distToDetector, yShift, rotYdeg, rotXdeg,
115 (geoTag && geoTag[0]) ? "_" : "", geoTag);
116
117 // ---- global geometry parameters ---------------------------------------
118 FairGeoLoader* geoLoad = new FairGeoLoader("TGeo", "FairGeoLoader");
119 FairGeoInterface* geoFace = geoLoad->getGeoInterface();
120
121 // ------- Load media from media file ----------------------------------
122 TString medFile = workDir + "/geometry/media.geo";
123 geoFace->setMediaFile(medFile);
124 geoFace->readMedia();
125 FairGeoMedia* geoMedia = geoFace->getMedia();
126 FairGeoBuilder* geoBuild = geoLoad->getGeoBuilder();
127 DefineRequiredMedia(geoMedia, geoBuild);
128
129 // -------------- Create geometry and global top volume --------------------
130 gGeoManager = (TGeoManager*)gROOT->FindObject("FAIRGeom");
131 gGeoManager->SetName(geoDetectorName + "_geom");
132
134 top->SetMedium(pMedAir);
135 gGeoManager->SetTopVolume(top);
136
138 ndetCommon->SetMedium(pMedAir);
139
143
147 ndetEnvelope->AddNode(detVolume, 0, new TGeoTranslation(0., 0., 0.));
148
149 // ---- material/slice volume prototypes (shared across all layers) --------
150 auto makeSliceVolume = [](const char* name, Double_t sizeX, Double_t sizeY, Double_t sizeZ, TGeoMedium* medium,
151 Color_t color) {
152 TGeoShape* shape = new TGeoBBox(name, Half(sizeX), Half(sizeY), Half(sizeZ));
153 TGeoVolume* vol = new TGeoVolume(name, shape);
154 vol->SetLineColor(color);
155 vol->SetFillColor(color);
156 if (!medium)
157 Fatal("create_ndet_geometry", "Invalid medium for volume '%s'", name);
158 vol->SetMedium(medium);
159 return vol;
160 };
161
162 TGeoVolume* volG10 =
166
167 // ---- helper: place the single cell of one layer --------------------------
168 // Module numbering: modNb = row*NColumns + column + layerIndex*NCellsPerLayer + 1
169 // (kNRows=kNColumns=1 here, so this is just layerIndex + 1, but the general
170 // formula is kept so this still works if the grid is ever made bigger again).
171 auto placeLayer = [&](Int_t layerIndex, Double_t zFrontFace) {
172 const Double_t zScintCenter = FrontToLocalZ(zFrontFace + Half(kScintSizeZ));
173 const Double_t zG10Center = FrontToLocalZ(zFrontFace + kScintSizeZ + Half(kG10SizeZ));
174
175 for (Int_t iy = 0; iy < kNRows; ++iy) {
176 for (Int_t ix = 0; ix < kNColumns; ++ix) {
177 const Int_t modNb = iy * kNColumns + ix + layerIndex * kNCellsPerLayer + 1;
178 const Int_t rowNb = iy + 1;
179 const Int_t columnNb = ix + 1;
180
183 TGeoVolume* moduleVolume = new TGeoVolume(BmnNdetGeoPar::fModuleVolumeName, moduleShape);
184 moduleVolume->SetMedium(pMedAir);
185 moduleVolume->SetName(
186 Form("%s_%d_%d_%d", BmnNdetGeoPar::fModuleVolumeName.Data(), rowNb, columnNb, layerIndex + 1));
187 moduleVolume->AddNode(volScint, modNb, new TGeoTranslation(0, 0, 0));
188
189 detVolume->AddNode(moduleVolume, modNb, new TGeoTranslation(0, 0, zScintCenter));
190 }
191 }
192
193 detVolume->AddNode(volG10, layerIndex + 1, new TGeoTranslation(0, 0, zG10Center));
194 };
195
196 for (Int_t layer = 0; layer < kNLayers; ++layer) {
197 placeLayer(layer, kScintFrontZ[layer]);
198 }
199
200 // ---- position and rotate the whole detector ------------------------------
201 TGeoRotation* rot = new TGeoRotation("rot");
202 rot->RotateX(rotXdeg);
203 rot->RotateY(rotYdeg);
204
205 Double_t local[3] = {0., 0., distToDetector + Half(kEnvelopeSizeZ)};
206 Double_t master[3] = {0., 0., 0.};
207 rot->LocalToMaster(local, master);
208 master[1] += yShift;
209
210 printf("NDet center: x=%.3f y=%.3f z=%.3f cm\n", master[0], master[1], master[2]);
211
212 TGeoCombiTrans* ndetTransform = new TGeoCombiTrans("ndetTransform", master[0], master[1], master[2], rot);
213 ndetCommon->AddNode(ndetEnvelope, 1, ndetTransform);
214 top->AddNode(ndetCommon, 0);
216
217 // --------------- Finish ----------------------------------------------
218 gGeoManager->CloseGeometry();
219 gGeoManager->CheckOverlaps(0.001);
220 gGeoManager->PrintOverlaps();
221 gGeoManager->Test();
222
223 TFile* geoFile = new TFile(geoFileName, "RECREATE");
224 top->Write();
225 geoFile->Close();
226
227 printf("Geometry written to: %s\n", geoFileName.Data());
228}
__m128 m
Definition P4_F32vec4.h:27
int Int_t
short Color_t
double Double_t
constexpr Bool_t kTRUE
kGreen
kBlue
void Fatal(const char *location, const char *msgfmt,...)
R__EXTERN TGeoManager * gGeoManager
#define gROOT
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
static const TString G10_name_NICA
static const TString fDetectorVolumeName
static const TString fEnvelopeVolumeName
static const TString fModuleVolumeName
static const TString fTopVolumeName
static const TString SensitiveVolume_name_NICA
static const TString fCommonVolumeName
virtual void SetFillColor(Color_t fcolor)
void Close(Option_t *option="") override
void RotateX(Double_t angle) override
void RotateY(Double_t angle) override
void LocalToMaster(const Double_t *local, Double_t *master) const override
void SetVisContainers(Bool_t flag=kTRUE) override
virtual TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="")
virtual void SetMedium(TGeoMedium *medium)
void SetLineColor(Color_t lcolor) override
virtual void SetName(const char *name)
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
const char * Data() const
TGeoMedium * pMedAir
TGeoMedium * pMedG10
TGeoMedium * pMedScint
TGeoMedium * pMedVacuum
void bmnloadlibs()
Definition bmnloadlibs.C:4
void DefineRequiredMedia(FairGeoMedia *geoMedia, FairGeoBuilder *geoBuild)
void create_rootgeom_HGND_run9(Double_t distToDetector=699.7, Double_t yShift=0.0, Double_t rotYdeg=-10.0, Double_t rotXdeg=0.0, const char *geoTag="")
HGND Run9 geometry creation macro Two identical layers (scintillator cell + PCB), no absorber between...
constexpr Double_t kScintFrontZ[kNLayers]
constexpr Double_t kEnvelopeSizeX
constexpr Double_t kScintSizeY
constexpr Int_t kNCellsPerLayer
constexpr Double_t kG10SizeY
constexpr Double_t kEnvelopeSizeZ
constexpr Int_t kNRows
constexpr Double_t kEnvelopeSizeY
constexpr Double_t kScintSizeZ
constexpr Double_t kEnvelopeMargin
constexpr Double_t kG10SizeZ
constexpr Int_t kNColumns
constexpr Double_t kG10SizeX
constexpr Double_t FrontToLocalZ(Double_t zFront)
constexpr Double_t Half(Double_t fullSize)
constexpr Double_t kScintSizeX
constexpr Int_t kNLayers