File indexing completed on 2025-12-17 09:22:08
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.contains(volume))
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.contains(volume->GetLogicalVolume()))
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 std::string assemblyname = "MVTXStave";
0260 if (Verbosity() > 0)
0261 {
0262 std::cout << "Geting the stave assembly named " << assemblyname << std::endl;
0263 }
0264 G4AssemblyVolume *av_ITSUStave = reader->GetAssembly(assemblyname);
0265
0266 for (unsigned short ilayer = 0; ilayer < n_Layers; ++ilayer)
0267 {
0268 if (m_IsLayerActive[ilayer])
0269 {
0270 if (Verbosity() > 0)
0271 {
0272 std::cout << std::endl;
0273 std::cout << " Constructing Layer " << ilayer << std::endl;
0274 }
0275 ConstructMvtx_Layer(ilayer, av_ITSUStave, trackerenvelope);
0276 }
0277 }
0278 FillPVArray(av_ITSUStave);
0279 SetDisplayProperty(av_ITSUStave);
0280
0281 return 0;
0282 }
0283
0284 int PHG4MvtxDetector::ConstructMvtx_Layer(int layer, G4AssemblyVolume *av_ITSUStave, G4LogicalVolume *&trackerenvelope)
0285 {
0286
0287
0288
0289
0290 int N_staves = m_N_staves[layer];
0291 G4double layer_nominal_radius = m_nominal_radius[layer];
0292 G4double phitilt = m_nominal_phitilt[layer];
0293 G4double phi0 = m_nominal_phi0[layer];
0294
0295 if (N_staves < 0)
0296 {
0297
0298
0299
0300 double arcstep = 12.25;
0301 double numstaves = 2.0 * M_PI * layer_nominal_radius / arcstep;
0302 N_staves = int(2.0 * M_PI * layer_nominal_radius / arcstep);
0303
0304
0305 if (Verbosity() > 0)
0306 {
0307 std::cout << " Calculated N_staves for layer "
0308 << " layer_nominal_radius " << layer_nominal_radius << " ITS arcstep " << arcstep << " circumference divided by arcstep " << numstaves << " N_staves " << N_staves << std::endl;
0309 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;
0310 }
0311 }
0312
0313 G4double phistep = get_phistep(layer);
0314 double z_location = 0.0;
0315
0316 if (Verbosity() > 0)
0317 {
0318 std::cout << " layer "
0319 << " layer_nominal_radius " << layer_nominal_radius << " N_staves " << N_staves << " phistep " << phistep << " phitilt " << phitilt << " phi0 " << phi0 << std::endl;
0320 }
0321
0322
0323
0324
0325 double phi_offset = M_PI / 2.0;
0326
0327 for (int iphi = 0; iphi < N_staves; iphi++)
0328 {
0329
0330
0331
0332 G4double phi_rotation = phi0 + (double) iphi * phistep;
0333
0334 G4RotationMatrix Ra;
0335 G4ThreeVector Ta;
0336
0337 if (Verbosity() > 0)
0338 {
0339 std::cout << "phi_offset = " << phi_offset << " iphi " << iphi << " phi_rotation = " << phi_rotation << " phitilt " << phitilt << std::endl;
0340 }
0341
0342
0343
0344 Ra.rotateZ(phi_rotation + phi_offset + phitilt);
0345
0346
0347 Ta.setX(layer_nominal_radius * cos(phi_rotation));
0348 Ta.setY(layer_nominal_radius * sin(phi_rotation));
0349 Ta.setZ(z_location);
0350
0351 if (Verbosity() > 0)
0352 {
0353 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;
0354 }
0355 G4Transform3D Tr(Ra, Ta);
0356
0357 av_ITSUStave->MakeImprint(trackerenvelope, Tr, 0, OverlapCheck());
0358 }
0359
0360 if (Verbosity() > 0)
0361 {
0362 std::cout << "This layer has a total of " << N_staves << " staves" << std::endl;
0363 }
0364 return 0;
0365 }
0366
0367 int PHG4MvtxDetector::ConstructMvtxPassiveVol(G4LogicalVolume *&lv)
0368 {
0369 if (Verbosity() > 0)
0370 {
0371 std::cout << " PHG4MvtxDetector::ConstructMvtxServices:" << std::endl;
0372 std::cout << std::endl;
0373 }
0374
0375
0376 PHG4MvtxSupport *mvtxSupportSystem = new PHG4MvtxSupport(this, m_DisplayAction, OverlapCheck());
0377 mvtxSupportSystem->ConstructMvtxSupport(lv);
0378
0379 delete mvtxSupportSystem;
0380
0381 return 0;
0382 }
0383
0384
0385 void PHG4MvtxDetector::SetDisplayProperty(G4AssemblyVolume *av)
0386 {
0387
0388
0389
0390 std::vector<G4VPhysicalVolume *>::iterator it = av->GetVolumesIterator();
0391
0392 int nDaughters = av->TotalImprintedVolumes();
0393 for (int i = 0; i < nDaughters; ++i, ++it)
0394 {
0395 if (Verbosity() >= 50)
0396 {
0397 std::cout << "SetDisplayProperty - AV[" << i << "] = " << (*it)->GetName() << std::endl;
0398 }
0399 G4VPhysicalVolume *pv = (*it);
0400
0401 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0402 SetDisplayProperty(worldLogical);
0403 }
0404 }
0405
0406
0407 void PHG4MvtxDetector::SetDisplayProperty(G4LogicalVolume *lv)
0408 {
0409 std::string material_name(lv->GetMaterial()->GetName());
0410
0411 if (Verbosity() >= 50)
0412 {
0413 std::cout << "SetDisplayProperty - LV " << lv->GetName() << " built with " << material_name << std::endl;
0414 }
0415 std::vector<std::string> matname = {"SI", "KAPTON", "ALUMINUM", "Carbon", "M60J3K", "WATER"};
0416 bool found = false;
0417 for (const std::string &nam : matname)
0418 {
0419 if (material_name.find(nam) != std::string::npos)
0420 {
0421 m_DisplayAction->AddVolume(lv, nam);
0422 if (Verbosity() >= 50)
0423 {
0424 std::cout << "SetDisplayProperty - LV " << lv->GetName() << " display with " << nam << std::endl;
0425 }
0426 found = true;
0427 break;
0428 }
0429 }
0430 if (!found)
0431 {
0432 m_DisplayAction->AddVolume(lv, "ANYTHING_ELSE");
0433 }
0434 int nDaughters = lv->GetNoDaughters();
0435 for (int i = 0; i < nDaughters; ++i)
0436 {
0437 G4VPhysicalVolume *pv = lv->GetDaughter(i);
0438
0439
0440
0441 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0442 SetDisplayProperty(worldLogical);
0443 }
0444 }
0445
0446 void PHG4MvtxDetector::AddGeometryNode()
0447 {
0448 int active = 0;
0449
0450
0451
0452
0453 if (std::any_of(m_IsLayerActive.begin(), m_IsLayerActive.end(), [](int isAct) { return isAct != 0; }))
0454 {
0455 active = 1;
0456 }
0457
0458 if (active)
0459 {
0460
0461 std::string geonode = "CYLINDERGEOM_" + ((m_SuperDetector != "NONE") ? m_SuperDetector : m_Detector);
0462 PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode(), geonode);
0463 if (!geo)
0464 {
0465 geo = new PHG4CylinderGeomContainer();
0466 PHNodeIterator iter(topNode());
0467 PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
0468 PHNodeIterator runiter(runNode);
0469 PHCompositeNode *geomNode = dynamic_cast<PHCompositeNode *>(runiter.findFirst("PHCompositeNode", "RECO_TRACKING_GEOMETRY"));
0470 if(!geomNode)
0471 {
0472 geomNode = new PHCompositeNode("RECO_TRACKING_GEOMETRY");
0473 runNode->addNode(geomNode);
0474 }
0475 PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(geo, geonode, "PHObject");
0476 geomNode->addNode(newNode);
0477 }
0478
0479
0480 for (unsigned short ilayer = 0; ilayer < n_Layers; ++ilayer)
0481 {
0482 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);
0483 geo->AddLayerGeom(ilayer, mygeom);
0484 }
0485 if (Verbosity())
0486 {
0487 geo->identify();
0488 }
0489 }
0490 }
0491
0492 void PHG4MvtxDetector::FillPVArray(G4AssemblyVolume *av)
0493 {
0494 if (Verbosity() > 0)
0495 {
0496 std::cout << "-- FillPVArray --" << std::endl;
0497 }
0498 std::vector<G4VPhysicalVolume *>::iterator it = av->GetVolumesIterator();
0499
0500 int nDaughters = av->TotalImprintedVolumes();
0501 for (int i = 0; i < nDaughters; ++i, ++it)
0502 {
0503 G4VPhysicalVolume *pv = (*it);
0504
0505 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0506
0507 if (pv->GetName().find("MVTXHalfStave_pv") != std::string::npos)
0508 {
0509 int layer = get_layer(m_StavePV.size());
0510 int stave = get_stave(m_StavePV.size());
0511
0512 m_StavePV.insert(std::make_pair(pv, std::make_tuple(layer, stave)));
0513
0514 if (Verbosity() > 0)
0515 {
0516 std::cout << "Mvtx layer id " << layer << std::endl;
0517 std::cout << "Stave in layer id " << stave << std::endl;
0518 std::cout << "Mvtx stave count " << m_StavePV.size() << std::endl;
0519 std::cout << "FillPVArray - AV[" << i << "] = " << (*it)->GetName() << std::endl;
0520 std::cout << " LV[" << i << "] = " << worldLogical->GetName() << std::endl;
0521 }
0522
0523 FindSensor(worldLogical);
0524 }
0525 else
0526 {
0527 if (Verbosity() > 0)
0528 {
0529 std::cout << "FillPVArray - AV[" << i << "] = " << (*it)->GetName() << std::endl;
0530 std::cout << " LV[" << i << "] = " << worldLogical->GetName() << std::endl;
0531 }
0532 }
0533 }
0534 }
0535
0536
0537 void PHG4MvtxDetector::FindSensor(G4LogicalVolume *lv)
0538 {
0539 int nDaughters = lv->GetNoDaughters();
0540 for (int i = 0; i < nDaughters; ++i)
0541 {
0542 G4VPhysicalVolume *pv = lv->GetDaughter(i);
0543 if (Verbosity() > 0)
0544 {
0545 std::cout << " PV[" << i << "]: " << pv->GetName() << std::endl;
0546 }
0547 if (pv->GetName().find("MVTXSensor_") != std::string::npos)
0548 {
0549 m_SensorPV.insert(pv);
0550
0551 if (Verbosity() > 0)
0552 {
0553 std::cout << " Adding Sensor Vol <" << pv->GetName() << " (" << m_SensorPV.size() << ")>" << std::endl;
0554 }
0555 }
0556
0557 G4LogicalVolume *worldLogical = pv->GetLogicalVolume();
0558
0559 if (Verbosity() > 0)
0560 {
0561 std::cout << " LV[" << i << "]: " << worldLogical->GetName() << std::endl;
0562 }
0563 FindSensor(worldLogical);
0564 }
0565 }