File indexing completed on 2025-08-05 08:18:13
0001 #include "PHG4MvtxDetector.h"
0002
0003 #include "PHG4MvtxMisalignment.h"
0004
0005 #include "PHG4MvtxDefs.h"
0006 #include "PHG4MvtxDisplayAction.h"
0007 #include "PHG4MvtxSupport.h"
0008
0009 #include <mvtx/CylinderGeom_Mvtx.h>
0010 #include <trackbase/MvtxDefs.h>
0011 #include <trackbase/TrkrDefs.h>
0012
0013 #include <g4detectors/PHG4CylinderGeomContainer.h>
0014
0015 #include <phparameter/PHParameters.h>
0016 #include <phparameter/PHParametersContainer.h>
0017
0018 #include <g4main/PHG4Detector.h> // for PHG4Detector
0019 #include <g4main/PHG4DisplayAction.h> // for PHG4DisplayAction
0020 #include <g4main/PHG4Subsystem.h> // for PHG4Subsystem
0021
0022 #include <phool/PHCompositeNode.h>
0023 #include <phool/PHIODataNode.h>
0024 #include <phool/PHNode.h> // for PHNode
0025 #include <phool/PHNodeIterator.h> // for PHNodeIterator
0026 #include <phool/PHObject.h> // for PHObject
0027 #include <phool/getClass.h>
0028
0029 #include <Geant4/G4AssemblyVolume.hh>
0030 #include <Geant4/G4LogicalVolume.hh>
0031 #include <Geant4/G4Material.hh>
0032 #include <Geant4/G4PVPlacement.hh>
0033 #include <Geant4/G4Polycone.hh>
0034 #include <Geant4/G4RotationMatrix.hh> // for G4RotationMatrix
0035 #include <Geant4/G4String.hh> // for G4String
0036 #include <Geant4/G4SystemOfUnits.hh>
0037 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
0038 #include <Geant4/G4Transform3D.hh> // for G4Transform3D
0039 #include <Geant4/G4Tubs.hh>
0040 #include <Geant4/G4Types.hh> // for G4double
0041 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
0042
0043 #include <Geant4/G4GDMLParser.hh>
0044 #include <Geant4/G4GDMLReadStructure.hh> // for G4GDMLReadStructure
0045
0046 #include <cmath>
0047 #include <cstdio> // for sprintf
0048 #include <iostream> // for operator<<, basic...
0049 #include <memory>
0050 #include <sstream>
0051 #include <utility> // for pair, make_pair
0052 #include <vector> // for vector, vector<>:...
0053
0054 namespace mvtxGeomDef
0055 {
0056 const double wrap_rmax = (107.7 + 0.3) * mm;
0057 const double wrap_rmin = 22 * mm;
0058 const double wrap_smallCylR = 55.00 * mm;
0059 const double wrap_CYSSFlgN_Z = (177.5 + 12.5) * mm;
0060 const double wrap_CYSSNose_Z = -245 * mm;
0061 const double wrap_CYSSHead_Z = -315 * mm;
0062 const double wrap_SBCyl_Z = -1800 * mm;
0063 }
0064
0065 PHG4MvtxDetector::PHG4MvtxDetector(PHG4Subsystem *subsys, PHCompositeNode *Node, const PHParametersContainer *_paramsContainer, const std::string &dnam, const bool applyMisalignment, const std::string& misalignmentfile)
0066 : PHG4Detector(subsys, Node, dnam)
0067 , m_DisplayAction(dynamic_cast<PHG4MvtxDisplayAction *>(subsys->GetDisplayAction()))
0068 , m_ParamsContainer(_paramsContainer)
0069 , m_StaveGeometryFile(_paramsContainer->GetParameters(PHG4MvtxDefs::GLOBAL)->get_string_param("stave_geometry_file"))
0070 , apply_misalignment(applyMisalignment)
0071 , m_misalignmentFile(misalignmentfile)
0072 {
0073 if (Verbosity() > 0)
0074 {
0075 std::cout << "PHG4MvtxDetector constructor called" << std::endl;
0076 }
0077
0078 for (int ilayer = 0; ilayer < n_Layers; ++ilayer)
0079 {
0080 const PHParameters *params = m_ParamsContainer->GetParameters(ilayer);
0081 m_IsLayerActive[ilayer] = params->get_int_param("active");
0082 m_IsLayerSupportActive[ilayer] = params->get_int_param("supportactive");
0083 m_IsBlackHole[ilayer] = params->get_int_param("blackhole");
0084 m_N_staves[ilayer] = params->get_int_param("N_staves");
0085 m_nominal_radius[ilayer] = params->get_double_param("layer_nominal_radius");
0086 m_nominal_phitilt[ilayer] = params->get_double_param("phitilt");
0087 m_nominal_phi0[ilayer] = params->get_double_param("phi0");
0088 m_SupportActiveFlag += m_IsLayerSupportActive[ilayer];
0089 }
0090 if (apply_misalignment)
0091 {
0092 std::cout << "PHG4MvtxDetector constructor: Apply Misalignment, get global displacement" << std::endl;
0093 PHG4MvtxMisalignment *m_MvtxMisalignment = new PHG4MvtxMisalignment();
0094 if(!m_misalignmentFile.empty())
0095 {
0096 std::cout << "loading mvtx survey geometry from " << m_misalignmentFile << std::endl;
0097 m_MvtxMisalignment->setAlignmentFile(m_misalignmentFile);
0098 }
0099 m_MvtxMisalignment->LoadMvtxStaveAlignmentParameters();
0100
0101 std::vector<double> v_globaldisplacement = m_MvtxMisalignment->get_GlobalDisplacement();
0102 m_GlobalDisplacementX = v_globaldisplacement[0];
0103 m_GlobalDisplacementY = v_globaldisplacement[1];
0104 m_GlobalDisplacementZ = v_globaldisplacement[2];
0105 delete m_MvtxMisalignment;
0106 }
0107
0108 if (Verbosity() > 0)
0109 {
0110 std::cout << "PHG4MvtxDetector constructor: making Mvtx detector. " << std::endl;
0111 }
0112 }
0113
0114 int PHG4MvtxDetector::IsSensor(G4VPhysicalVolume *volume) const
0115 {
0116
0117
0118 if (m_SensorPV.find(volume) != m_SensorPV.end())
0119 {
0120 if (Verbosity() > 0)
0121 {
0122 std::cout << " -- PHG4MvtxTDetector::IsSensor --" << std::endl;
0123 std::cout << " volume Name : " << volume->GetName() << std::endl;
0124 std::cout << " -----------------------------------------" << std::endl;
0125 }
0126 return 1;
0127 }
0128 if (m_SupportActiveFlag)
0129 {
0130 if (m_SupportLV.find(volume->GetLogicalVolume()) != m_SupportLV.end())
0131 {
0132 return -1;
0133 }
0134 }
0135 return 0;
0136 }
0137
0138 int PHG4MvtxDetector::IsInMvtx(G4VPhysicalVolume *volume, int &layer, int &stave) const
0139 {
0140
0141
0142
0143 auto iter = m_StavePV.find(volume);
0144 if (iter != m_StavePV.end())
0145 {
0146 std::tie(layer, stave) = iter->second;
0147 if (Verbosity() > 0)
0148 {
0149 std::cout << " -- PHG4MvtxDetector::IsInMvtx --" << std::endl;
0150 std::cout << " layer: " << layer << std::endl;
0151 std::cout << " stave: " << stave << std::endl;
0152 std::cout << " volume Name : " << volume->GetName() << std::endl;
0153 std::cout << " stave Name : " << iter->first->GetName() << std::endl;
0154 std::cout << " -----------------------------------------" << std::endl;
0155 }
0156 return 1;
0157 }
0158
0159 return 0;
0160 }
0161
0162 int PHG4MvtxDetector::get_layer(int index) const
0163 {
0164
0165
0166 int lay = 0;
0167 while (!(index < m_N_staves[lay]))
0168 {
0169 index -= m_N_staves[lay];
0170 lay++;
0171 }
0172 return lay;
0173 }
0174
0175 int PHG4MvtxDetector::get_stave(int index) const
0176 {
0177
0178 int lay = 0;
0179 while (!(index < m_N_staves[lay]))
0180 {
0181 index -= m_N_staves[lay];
0182 lay++;
0183 }
0184 return index;
0185 }
0186
0187 void PHG4MvtxDetector::ConstructMe(G4LogicalVolume *logicWorld)
0188 {
0189
0190 if (Verbosity() > 0)
0191 {
0192 std::cout << std::endl
0193 << "PHG4MvtxDetector::Construct called for Mvtx " << std::endl;
0194 }
0195
0196 const G4int numZPlanes = 4;
0197 const G4double zPlane[numZPlanes] = {mvtxGeomDef::wrap_SBCyl_Z, mvtxGeomDef::wrap_CYSSHead_Z, mvtxGeomDef::wrap_CYSSNose_Z, mvtxGeomDef::wrap_CYSSFlgN_Z};
0198
0199 const G4double rInner[numZPlanes] = {
0200 apply_misalignment ? mvtxGeomDef::wrap_rmin + 0.822 * mm : mvtxGeomDef::wrap_rmin,
0201 apply_misalignment ? mvtxGeomDef::wrap_rmin + 0.822 * mm : mvtxGeomDef::wrap_rmin,
0202 apply_misalignment ? mvtxGeomDef::wrap_rmin + 0.822 * mm : mvtxGeomDef::wrap_rmin,
0203 apply_misalignment ? mvtxGeomDef::wrap_rmin + 0.822 * mm : mvtxGeomDef::wrap_rmin
0204 };
0205
0206 const G4double rOuter[numZPlanes] = {mvtxGeomDef::wrap_rmax, mvtxGeomDef::wrap_rmax, mvtxGeomDef::wrap_smallCylR, mvtxGeomDef::wrap_smallCylR};
0207
0208 auto mvtxWrapSol = new G4Polycone("sol_MVTX_Wrapper", 0, 2.0 * M_PI, numZPlanes, zPlane, rInner, rOuter);
0209
0210 auto world_mat = logicWorld->GetMaterial();
0211
0212 auto logicMVTX = new G4LogicalVolume(mvtxWrapSol, world_mat, "log_MVTX_Wrapper");
0213
0214 G4RotationMatrix Ra;
0215 G4ThreeVector Ta;
0216
0217 if (apply_misalignment)
0218 {
0219 if (Verbosity() > 1) {
0220 std::cout << "PHG4MvtxDetector::Apply Global Displacement to the MVTX_Wrapper: " << m_GlobalDisplacementX << " " << m_GlobalDisplacementY << " " << m_GlobalDisplacementZ << std::endl;
0221 }
0222
0223 Ta.setX(m_GlobalDisplacementX);
0224 Ta.setY(m_GlobalDisplacementY);
0225 Ta.setZ(m_GlobalDisplacementZ);
0226 }
0227
0228 G4Transform3D Tr(Ra, Ta);
0229 new G4PVPlacement(Tr, logicMVTX, "MVTX_Wrapper", logicWorld, false, 0, false);
0230
0231
0232
0233
0234 ConstructMvtx(logicMVTX);
0235 ConstructMvtxPassiveVol(logicMVTX);
0236
0237 AddGeometryNode();
0238 return;
0239 }
0240
0241 int PHG4MvtxDetector::ConstructMvtx(G4LogicalVolume *trackerenvelope)
0242 {
0243 if (Verbosity() > 0)
0244 {
0245 std::cout << " PHG4MvtxDetector::ConstructMvtx:" << std::endl;
0246 std::cout << std::endl;
0247 }
0248
0249
0250
0251
0252
0253
0254 std::unique_ptr<G4GDMLReadStructure> reader(new G4GDMLReadStructure());
0255 G4GDMLParser gdmlParser(reader.get());
0256 gdmlParser.Read(m_StaveGeometryFile, false);
0257
0258
0259 char assemblyname[500];
0260 sprintf(assemblyname, "MVTXStave");
0261
0262 if (Verbosity() > 0)
0263 {
0264 std::cout << "Geting the stave assembly named " << assemblyname << std::endl;
0265 }
0266 G4AssemblyVolume *av_ITSUStave = reader->GetAssembly(assemblyname);
0267
0268 for (unsigned short ilayer = 0; ilayer < n_Layers; ++ilayer)
0269 {
0270 if (m_IsLayerActive[ilayer])
0271 {
0272 if (Verbosity() > 0)
0273 {
0274 std::cout << std::endl;
0275 std::cout << " Constructing Layer " << ilayer << std::endl;
0276 }
0277 ConstructMvtx_Layer(ilayer, av_ITSUStave, trackerenvelope);
0278 }
0279 }
0280 FillPVArray(av_ITSUStave);
0281 SetDisplayProperty(av_ITSUStave);
0282
0283 return 0;
0284 }
0285
0286 int PHG4MvtxDetector::ConstructMvtx_Layer(int layer, G4AssemblyVolume *av_ITSUStave, G4LogicalVolume *&trackerenvelope)
0287 {
0288
0289
0290
0291
0292 int N_staves = m_N_staves[layer];
0293 G4double layer_nominal_radius = m_nominal_radius[layer];
0294 G4double phitilt = m_nominal_phitilt[layer];
0295 G4double phi0 = m_nominal_phi0[layer];
0296
0297 if (N_staves < 0)
0298 {
0299
0300
0301
0302 double arcstep = 12.25;
0303 double numstaves = 2.0 * M_PI * layer_nominal_radius / arcstep;
0304 N_staves = int(2.0 * M_PI * layer_nominal_radius / arcstep);
0305
0306
0307 if (Verbosity() > 0)
0308 {
0309 std::cout << " Calculated N_staves for layer "
0310 << " layer_nominal_radius " << layer_nominal_radius << " ITS arcstep " << arcstep << " circumference divided by arcstep " << numstaves << " N_staves " << N_staves << std::endl;
0311 std::cout << "A radius for this layer of " << (double) N_staves * arcstep / (2.0 * M_PI) + 0.01 << " or " << (double) (N_staves + 1) * arcstep / (2.0 * M_PI) + 0.01 << " would produce perfect stave spacing" << std::endl;
0312 }
0313 }
0314
0315 G4double phistep = get_phistep(layer);
0316 double z_location = 0.0;
0317
0318 if (Verbosity() > 0)
0319 {
0320 std::cout << " layer "
0321 << " layer_nominal_radius " << layer_nominal_radius << " N_staves " << N_staves << " phistep " << phistep << " phitilt " << phitilt << " phi0 " << phi0 << std::endl;
0322 }
0323
0324
0325
0326
0327 double phi_offset = M_PI / 2.0;
0328
0329 for (int iphi = 0; iphi < N_staves; iphi++)
0330 {
0331
0332
0333
0334 G4double phi_rotation = phi0 + (double) iphi * phistep;
0335
0336 G4RotationMatrix Ra;
0337 G4ThreeVector Ta;
0338
0339 if (Verbosity() > 0)
0340 {
0341 std::cout << "phi_offset = " << phi_offset << " iphi " << iphi << " phi_rotation = " << phi_rotation << " phitilt " << phitilt << std::endl;
0342 }
0343
0344
0345
0346 Ra.rotateZ(phi_rotation + phi_offset + phitilt);
0347
0348
0349 Ta.setX(layer_nominal_radius * cos(phi_rotation));
0350 Ta.setY(layer_nominal_radius * sin(phi_rotation));
0351 Ta.setZ(z_location);
0352
0353 if (Verbosity() > 0)
0354 {
0355 std::cout << " iphi " << iphi << " phi_rotation " << phi_rotation << " x " << layer_nominal_radius * cos(phi_rotation) << " y " << layer_nominal_radius * sin(phi_rotation) << " z " << z_location << std::endl;
0356 }
0357 G4Transform3D Tr(Ra, Ta);
0358
0359 av_ITSUStave->MakeImprint(trackerenvelope, Tr, 0, OverlapCheck());
0360 }
0361
0362 if (Verbosity() > 0)
0363 {
0364 std::cout << "This layer has a total of " << N_staves << " staves" << std::endl;
0365 }
0366 return 0;
0367 }
0368
0369 int PHG4MvtxDetector::ConstructMvtxPassiveVol(G4LogicalVolume *&lv)
0370 {
0371 if (Verbosity() > 0)
0372 {
0373 std::cout << " PHG4MvtxDetector::ConstructMvtxServices:" << std::endl;
0374 std::cout << std::endl;
0375 }
0376
0377
0378 PHG4MvtxSupport *mvtxSupportSystem = new PHG4MvtxSupport(this, m_DisplayAction, OverlapCheck());
0379 mvtxSupportSystem->ConstructMvtxSupport(lv);
0380
0381 delete mvtxSupportSystem;
0382
0383 return 0;
0384 }
0385
0386
0387 void PHG4MvtxDetector::SetDisplayProperty(G4AssemblyVolume *av)
0388 {
0389
0390
0391
0392 std::vector<G4VPhysicalVolume *>::iterator it = av->GetVolumesIterator();
0393
0394 int nDaughters = av->TotalImprintedVolumes();
0395 for (int i = 0; i < nDaughters; ++i, ++it)
0396 {
0397 if (Verbosity() >= 50)
0398 {
0399 std::cout << "SetDisplayProperty - AV[" << i << "] = " << (*it)->GetName() << std::endl;
0400 }
0401 G4VPhysicalVolume *pv = (*it);
0402
0403 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0404 SetDisplayProperty(worldLogical);
0405 }
0406 }
0407
0408
0409 void PHG4MvtxDetector::SetDisplayProperty(G4LogicalVolume *lv)
0410 {
0411 std::string material_name(lv->GetMaterial()->GetName());
0412
0413 if (Verbosity() >= 50)
0414 {
0415 std::cout << "SetDisplayProperty - LV " << lv->GetName() << " built with " << material_name << std::endl;
0416 }
0417 std::vector<std::string> matname = {"SI", "KAPTON", "ALUMINUM", "Carbon", "M60J3K", "WATER"};
0418 bool found = false;
0419 for (const std::string &nam : matname)
0420 {
0421 if (material_name.find(nam) != std::string::npos)
0422 {
0423 m_DisplayAction->AddVolume(lv, nam);
0424 if (Verbosity() >= 50)
0425 {
0426 std::cout << "SetDisplayProperty - LV " << lv->GetName() << " display with " << nam << std::endl;
0427 }
0428 found = true;
0429 break;
0430 }
0431 }
0432 if (!found)
0433 {
0434 m_DisplayAction->AddVolume(lv, "ANYTHING_ELSE");
0435 }
0436 int nDaughters = lv->GetNoDaughters();
0437 for (int i = 0; i < nDaughters; ++i)
0438 {
0439 G4VPhysicalVolume *pv = lv->GetDaughter(i);
0440
0441
0442
0443 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0444 SetDisplayProperty(worldLogical);
0445 }
0446 }
0447
0448 void PHG4MvtxDetector::AddGeometryNode()
0449 {
0450 int active = 0;
0451
0452
0453
0454
0455 if (std::any_of(m_IsLayerActive.begin(), m_IsLayerActive.end(), [](int isAct) { return isAct != 0; }))
0456 {
0457 active = 1;
0458 }
0459
0460 if (active)
0461 {
0462
0463 std::string geonode = "CYLINDERGEOM_" + ((m_SuperDetector != "NONE") ? m_SuperDetector : m_Detector);
0464 PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode(), geonode);
0465 if (!geo)
0466 {
0467 geo = new PHG4CylinderGeomContainer();
0468 PHNodeIterator iter(topNode());
0469 PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
0470 PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(geo, geonode, "PHObject");
0471 runNode->addNode(newNode);
0472 }
0473
0474
0475 for (unsigned short ilayer = 0; ilayer < n_Layers; ++ilayer)
0476 {
0477 CylinderGeom_Mvtx *mygeom = new CylinderGeom_Mvtx(ilayer, m_N_staves[ilayer], m_nominal_radius[ilayer] / cm, get_phistep(ilayer) / rad, m_nominal_phitilt[ilayer] / rad, m_nominal_phi0[ilayer] / rad);
0478 geo->AddLayerGeom(ilayer, mygeom);
0479 }
0480 if (Verbosity())
0481 {
0482 geo->identify();
0483 }
0484 }
0485 }
0486
0487 void PHG4MvtxDetector::FillPVArray(G4AssemblyVolume *av)
0488 {
0489 if (Verbosity() > 0)
0490 {
0491 std::cout << "-- FillPVArray --" << std::endl;
0492 }
0493 std::vector<G4VPhysicalVolume *>::iterator it = av->GetVolumesIterator();
0494
0495 int nDaughters = av->TotalImprintedVolumes();
0496 for (int i = 0; i < nDaughters; ++i, ++it)
0497 {
0498 G4VPhysicalVolume *pv = (*it);
0499
0500 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0501
0502 if (pv->GetName().find("MVTXHalfStave_pv") != std::string::npos)
0503 {
0504 int layer = get_layer(m_StavePV.size());
0505 int stave = get_stave(m_StavePV.size());
0506
0507 m_StavePV.insert(std::make_pair(pv, std::make_tuple(layer, stave)));
0508
0509 if (Verbosity() > 0)
0510 {
0511 std::cout << "Mvtx layer id " << layer << std::endl;
0512 std::cout << "Stave in layer id " << stave << std::endl;
0513 std::cout << "Mvtx stave count " << m_StavePV.size() << std::endl;
0514 std::cout << "FillPVArray - AV[" << i << "] = " << (*it)->GetName() << std::endl;
0515 std::cout << " LV[" << i << "] = " << worldLogical->GetName() << std::endl;
0516 }
0517
0518 FindSensor(worldLogical);
0519 }
0520 else
0521 {
0522 if (Verbosity() > 0)
0523 {
0524 std::cout << "FillPVArray - AV[" << i << "] = " << (*it)->GetName() << std::endl;
0525 std::cout << " LV[" << i << "] = " << worldLogical->GetName() << std::endl;
0526 }
0527 }
0528 }
0529 }
0530
0531
0532 void PHG4MvtxDetector::FindSensor(G4LogicalVolume *lv)
0533 {
0534 int nDaughters = lv->GetNoDaughters();
0535 for (int i = 0; i < nDaughters; ++i)
0536 {
0537 G4VPhysicalVolume *pv = lv->GetDaughter(i);
0538 if (Verbosity() > 0)
0539 {
0540 std::cout << " PV[" << i << "]: " << pv->GetName() << std::endl;
0541 }
0542 if (pv->GetName().find("MVTXSensor_") != std::string::npos)
0543 {
0544 m_SensorPV.insert(pv);
0545
0546 if (Verbosity() > 0)
0547 {
0548 std::cout << " Adding Sensor Vol <" << pv->GetName() << " (" << m_SensorPV.size() << ")>" << std::endl;
0549 }
0550 }
0551
0552 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0553
0554 if (Verbosity() > 0)
0555 {
0556 std::cout << " LV[" << i << "]: " << worldLogical->GetName() << std::endl;
0557 }
0558 FindSensor(worldLogical);
0559 }
0560 }