File indexing completed on 2025-12-17 09:22:07
0001
0002
0003
0004
0005
0006
0007 #include "PHG4MicromegasDetector.h"
0008
0009 #include "PHG4MicromegasDisplayAction.h"
0010 #include "PHG4MicromegasSurvey.h"
0011
0012 #include <phparameter/PHParameters.h>
0013
0014 #include <g4detectors/PHG4CylinderGeomContainer.h>
0015
0016 #include <g4main/PHG4Detector.h>
0017 #include <g4main/PHG4Subsystem.h>
0018
0019 #include <micromegas/CylinderGeomMicromegas.h>
0020
0021 #include <phool/PHCompositeNode.h>
0022 #include <phool/PHIODataNode.h>
0023 #include <phool/PHNode.h> // for PHNode
0024 #include <phool/PHNodeIterator.h> // for PHNodeIterator
0025 #include <phool/PHObject.h> // for PHObject
0026 #include <phool/getClass.h>
0027 #include <phool/recoConsts.h>
0028
0029 #include <Geant4/G4Box.hh>
0030 #include <Geant4/G4Color.hh>
0031 #include <Geant4/G4LogicalVolume.hh>
0032 #include <Geant4/G4Material.hh>
0033 #include <Geant4/G4PVPlacement.hh>
0034 #include <Geant4/G4String.hh> // for G4String
0035 #include <Geant4/G4SystemOfUnits.hh>
0036 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
0037 #include <Geant4/G4Tubs.hh>
0038 #include <Geant4/G4Types.hh> // for G4double
0039 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
0040 #include <Geant4/G4VSolid.hh> // for G4VSolid
0041
0042 #include <cmath>
0043 #include <iostream>
0044 #include <numeric>
0045 #include <tuple> // for make_tuple, tuple
0046 #include <utility> // for pair, make_pair
0047 #include <vector> // for vector
0048
0049 namespace
0050 {
0051 template <class T>
0052 constexpr T square(const T& x)
0053 {
0054 return x * x;
0055 }
0056 template <class T>
0057 inline T get_r(const T& x, const T& y)
0058 {
0059 return std::sqrt(square(x) + square(y));
0060 }
0061 }
0062
0063
0064 PHG4MicromegasDetector::PHG4MicromegasDetector(PHG4Subsystem* subsys, PHCompositeNode* Node, PHParameters* parameters, const std::string& dnam)
0065 : PHG4Detector(subsys, Node, dnam)
0066 , m_DisplayAction(dynamic_cast<PHG4MicromegasDisplayAction*>(subsys->GetDisplayAction()))
0067 , m_Params(parameters)
0068 , m_ActiveFlag(m_Params->get_int_param("active"))
0069 , m_SupportActiveFlag(m_Params->get_int_param("supportactive"))
0070 {
0071 setup_tiles();
0072 }
0073
0074
0075 int PHG4MicromegasDetector::IsInDetector(G4VPhysicalVolume* volume) const
0076 {
0077 if (m_ActiveFlag)
0078 {
0079 if (m_activeVolumes.contains(volume))
0080 {
0081 return 1;
0082 }
0083 }
0084 if (m_SupportActiveFlag)
0085 {
0086 if (m_passiveVolumes.contains(volume))
0087 {
0088 return -1;
0089 }
0090 }
0091 return 0;
0092 }
0093
0094
0095 int PHG4MicromegasDetector::get_layer(G4VPhysicalVolume* volume) const
0096 {
0097 const auto iter = m_activeVolumes.find(volume);
0098 return iter == m_activeVolumes.end() ? -1 : iter->second;
0099 }
0100
0101
0102 int PHG4MicromegasDetector::get_tileid(G4VPhysicalVolume* volume) const
0103 {
0104 const auto iter = m_tiles_map.find(volume);
0105 return iter == m_tiles_map.end() ? -1 : iter->second;
0106 }
0107
0108
0109 void PHG4MicromegasDetector::ConstructMe(G4LogicalVolume* logicWorld)
0110 {
0111 create_materials();
0112 construct_micromegas(logicWorld);
0113 add_geometry_node();
0114 }
0115
0116
0117 void PHG4MicromegasDetector::Print(const std::string& what) const
0118 {
0119 std::cout << "PHG4Micromegas Detector:" << std::endl;
0120 if (what == "ALL" || what == "VOLUME")
0121 {
0122 std::cout << "Version 0.1" << std::endl;
0123 std::cout << "Parameters:" << std::endl;
0124 m_Params->Print();
0125 }
0126 return;
0127 }
0128
0129
0130 void PHG4MicromegasDetector::setup_tiles()
0131 {
0132
0133 m_tiles.clear();
0134
0135
0136
0137 static constexpr double tile_length = 54.2;
0138 static constexpr double tile_width = 31.6;
0139
0140 {
0141
0142 static constexpr double phi = 3. * M_PI / 2;
0143
0144
0145 for (const double& tile_z : {-84.6, -28.2, 28.2, 84.6})
0146 {
0147 m_tiles.emplace_back(phi, tile_z, tile_width / CylinderGeomMicromegas::reference_radius, tile_length);
0148 }
0149 }
0150
0151 {
0152
0153 for (const double& phi : {4. * M_PI / 3, 5. * M_PI / 3})
0154 {
0155
0156 for (const double& tile_z : {-37.1, 37.1})
0157 {
0158 m_tiles.emplace_back(phi, tile_z, tile_width / CylinderGeomMicromegas::reference_radius, tile_length);
0159 }
0160 }
0161 }
0162 }
0163
0164
0165 void PHG4MicromegasDetector::create_materials() const
0166 {
0167
0168
0169 auto *G4_N = GetDetectorMaterial("G4_N");
0170 auto *G4_O = GetDetectorMaterial("G4_O");
0171 auto *G4_C = GetDetectorMaterial("G4_C");
0172 auto *G4_H = GetDetectorMaterial("G4_H");
0173 auto *G4_Si = GetDetectorMaterial("G4_Si");
0174 auto *G4_Ar = GetDetectorMaterial("G4_Ar");
0175 auto *G4_Cr = GetDetectorMaterial("G4_Cr");
0176 auto *G4_Fe = GetDetectorMaterial("G4_Fe");
0177 auto *G4_Mn = GetDetectorMaterial("G4_Mn");
0178 auto *G4_Ni = GetDetectorMaterial("G4_Ni");
0179 auto *G4_Cu = GetDetectorMaterial("G4_Cu");
0180
0181
0182
0183 static const G4double temperature = 298.15 * kelvin;
0184 static const G4double pressure = 1. * atmosphere;
0185
0186
0187 if (!GetDetectorMaterial("mmg_FR4", false))
0188 {
0189 auto *mmg_FR4 = new G4Material("mmg_FR4", 1.860 * g / cm3, 4, kStateSolid);
0190 mmg_FR4->AddMaterial(G4_C, 0.43550);
0191 mmg_FR4->AddMaterial(G4_H, 0.03650);
0192 mmg_FR4->AddMaterial(G4_O, 0.28120);
0193 mmg_FR4->AddMaterial(G4_Si, 0.24680);
0194 }
0195
0196
0197 if (!GetDetectorMaterial("mmg_Kapton", false))
0198 {
0199 auto *mmg_Kapton = new G4Material("mmg_Kapton", 1.420 * g / cm3, 4, kStateSolid);
0200 mmg_Kapton->AddMaterial(G4_C, 0.6911330);
0201 mmg_Kapton->AddMaterial(G4_H, 0.0263620);
0202 mmg_Kapton->AddMaterial(G4_N, 0.0732700);
0203 mmg_Kapton->AddMaterial(G4_O, 0.2092350);
0204 }
0205
0206
0207 if (!GetDetectorMaterial("mmg_Gas", false))
0208 {
0209 auto *mmg_Gas = new G4Material("mmg_Gas", 0.00170335 * g / cm3, 3, kStateGas, temperature, pressure);
0210 mmg_Gas->AddMaterial(G4_Ar, 0.900);
0211 mmg_Gas->AddMaterial(G4_C, 0.0826586);
0212 mmg_Gas->AddMaterial(G4_H, 0.0173414);
0213 }
0214
0215
0216 if (!GetDetectorMaterial("mmg_Mesh", false))
0217 {
0218 auto *mmg_Mesh = new G4Material("mmg_Mesh", 2.8548 * g / cm3, 5, kStateSolid);
0219 mmg_Mesh->AddMaterial(G4_Cr, 0.1900);
0220 mmg_Mesh->AddMaterial(G4_Fe, 0.6800);
0221 mmg_Mesh->AddMaterial(G4_Mn, 0.0200);
0222 mmg_Mesh->AddMaterial(G4_Ni, 0.1000);
0223 mmg_Mesh->AddMaterial(G4_Si, 0.0100);
0224 }
0225
0226
0227 if (!GetDetectorMaterial("mmg_Strips", false))
0228 {
0229 new G4Material("mmg_Strips", 5.248414 * g / cm3, G4_Cu, kStateSolid);
0230 }
0231
0232
0233 if (!GetDetectorMaterial("mmg_ResistPaste", false))
0234 {
0235 new G4Material("mmg_ResistPaste", 0.77906 * g / cm3, G4_C, kStateSolid);
0236 }
0237 }
0238
0239
0240 void PHG4MicromegasDetector::construct_micromegas(G4LogicalVolume* logicWorld)
0241 {
0242
0243
0244
0245 static constexpr double inner_radius = 83.197 * cm;
0246
0247
0248
0249
0250
0251 double radius_phi_mean = 0;
0252 double radius_z_mean = 0;
0253
0254
0255 PHG4MicromegasSurvey micromegas_survey;
0256 const bool apply_survey = m_Params->get_int_param("apply_survey");
0257 std::cout << "PHG4MicromegasDetector::construct_micromegas - apply_survey: " << apply_survey << std::endl;
0258
0259
0260
0261 for (size_t tileid = 0; tileid < m_tiles.size(); ++tileid)
0262 {
0263
0264 const auto& tile = m_tiles[tileid];
0265
0266
0267 auto *const tile_logic_phi = construct_micromegas_tile(tileid, MicromegasDefs::SegmentationType::SEGMENTATION_PHI);
0268 const double tile_thickness_phi = static_cast<G4Box*>(tile_logic_phi->GetSolid())->GetXHalfLength() * 2;
0269
0270 {
0271
0272 const double centerZ = tile.m_centerZ * cm;
0273 const double centerPhi = tile.m_centerPhi;
0274
0275 G4RotationMatrix rotation;
0276 rotation.rotateZ(centerPhi * radian);
0277
0278
0279 double radius_phi = inner_radius + tile_thickness_phi / 2;
0280 const G4ThreeVector center(
0281 radius_phi * std::cos(centerPhi),
0282 radius_phi * std::sin(centerPhi),
0283 centerZ);
0284
0285 G4Transform3D transform(rotation, center);
0286
0287 if (apply_survey)
0288 {
0289
0290 const auto survey_transform = micromegas_survey.get_transformation(m_FirstLayer, tileid);
0291 transform = survey_transform * transform;
0292
0293
0294 const auto translation = transform.getTranslation();
0295 radius_phi = get_r(translation.x(), translation.y());
0296 }
0297
0298
0299 radius_phi_mean += radius_phi;
0300
0301 const auto tilename = GetName() + "_tile_" + std::to_string(tileid) + "_phi";
0302 new G4PVPlacement(transform, tile_logic_phi, tilename + "_phys", logicWorld, false, 0, OverlapCheck());
0303 }
0304
0305
0306 auto *const tile_logic_z = construct_micromegas_tile(tileid, MicromegasDefs::SegmentationType::SEGMENTATION_Z);
0307 const double tile_thickness_z = static_cast<G4Box*>(tile_logic_z->GetSolid())->GetXHalfLength() * 2;
0308
0309 {
0310
0311 const double centerZ = tile.m_centerZ * cm;
0312 const double centerPhi = tile.m_centerPhi;
0313
0314 G4RotationMatrix rotation;
0315 rotation.rotateZ(centerPhi * radian);
0316
0317 double radius_z = inner_radius + tile_thickness_phi + tile_thickness_z / 2;
0318 const G4ThreeVector center(
0319 radius_z * std::cos(centerPhi),
0320 radius_z * std::sin(centerPhi),
0321 centerZ);
0322
0323 G4Transform3D transform(rotation, center);
0324
0325 if (apply_survey)
0326 {
0327
0328 const auto survey_transform = micromegas_survey.get_transformation(m_FirstLayer + 1, tileid);
0329 transform = survey_transform * transform;
0330
0331
0332 const auto translation = transform.getTranslation();
0333 radius_z = get_r(translation.x(), translation.y());
0334 }
0335
0336 radius_z_mean += radius_z;
0337
0338 const auto tilename = GetName() + "_tile_" + std::to_string(tileid) + "_z";
0339 new G4PVPlacement(transform, tile_logic_z, tilename + "_phys", logicWorld, false, 0, OverlapCheck());
0340 }
0341 }
0342
0343
0344 radius_phi_mean /= m_tiles.size();
0345 m_layer_radius.at(m_FirstLayer) += radius_phi_mean / cm;
0346
0347 radius_z_mean /= m_tiles.size();
0348 m_layer_radius.at(m_FirstLayer + 1) += radius_z_mean / cm;
0349
0350 if (Verbosity())
0351 {
0352 std::cout << "PHG4MicromegasDetector::ConstructMe - first layer: " << m_FirstLayer << std::endl;
0353 for (const auto& pair : m_activeVolumes)
0354 {
0355 std::cout << "PHG4MicromegasDetector::ConstructMe - layer: " << pair.second << " volume: " << pair.first->GetName() << std::endl;
0356 }
0357 }
0358
0359 return;
0360 }
0361
0362
0363 G4LogicalVolume* PHG4MicromegasDetector::construct_micromegas_tile(int tileid, MicromegasDefs::SegmentationType segmentation_type)
0364 {
0365
0366
0367
0368
0369
0370 enum class Component
0371 {
0372 PCB,
0373 CuStrips,
0374 KaptonStrips,
0375 ResistiveStrips,
0376 Gas1,
0377 Mesh,
0378 Gas2,
0379 DriftCuElectrode,
0380 DriftKapton,
0381 DriftCarbon,
0382 FeeSupport
0383 };
0384
0385
0386 struct LayerStruct
0387 {
0388
0389 LayerStruct(float thickness, G4Material* material, const G4Colour& color, double dy, double dz, double y_offset, double z_offset)
0390 : m_thickness(thickness)
0391 , m_material(material)
0392 , m_color(color)
0393 , m_dy(dy)
0394 , m_dz(dz)
0395 , m_y_offset(y_offset)
0396 , m_z_offset(z_offset)
0397 {
0398 }
0399
0400
0401 float m_thickness = 0;
0402
0403
0404 G4Material* m_material = nullptr;
0405
0406
0407 G4Colour m_color = 0;
0408
0409
0410 double m_dy = 0;
0411
0412
0413 double m_dz = 0;
0414
0415
0416 double m_y_offset = 0;
0417
0418
0419 double m_z_offset = 0;
0420
0421 };
0422
0423
0424 const std::map<Component, LayerStruct> layer_map =
0425 {
0426
0427
0428 {Component::PCB, LayerStruct(1.0 * mm, GetDetectorMaterial("mmg_FR4"), G4Colour::Green(), 316 * mm, 542 * mm, 0, 0)},
0429 {Component::CuStrips, LayerStruct(12. * micrometer, GetDetectorMaterial("mmg_Strips"), G4Colour::Brown(), 256 * mm, 512 * mm, -15 * mm, 0)},
0430 {Component::KaptonStrips, LayerStruct(50. * micrometer, GetDetectorMaterial("mmg_Kapton"), G4Colour::Brown(), 256 * mm, 512 * mm, -15 * mm, 0)},
0431 {Component::ResistiveStrips, LayerStruct(20. * micrometer, GetDetectorMaterial("mmg_ResistPaste"), G4Colour::Black(), 256 * mm, 512 * mm, -15 * mm, 0)},
0432 {Component::Gas1, LayerStruct(120. * micrometer, GetDetectorMaterial("mmg_Gas"), G4Colour::Grey(), 256 * mm, 512 * mm, -15 * mm, 0)},
0433
0434 {Component::Mesh, LayerStruct(18. * 0.8 * micrometer, GetDetectorMaterial("mmg_Mesh"), G4Colour::White(), 256 * mm, 512 * mm, -15 * mm, 0)},
0435 {Component::Gas2, LayerStruct(3. * mm, GetDetectorMaterial("mmg_Gas"), G4Colour::Grey(), 256 * mm, 512 * mm, -15 * mm, 0)},
0436 {Component::DriftCuElectrode, LayerStruct(15. * micrometer, GetDetectorMaterial("G4_Cu"), G4Colour::Brown(), 256 * mm, 512 * mm, -15 * mm, 0)},
0437 {Component::DriftKapton, LayerStruct(50. * micrometer, GetDetectorMaterial("mmg_Kapton"), G4Colour::Brown(), 256 * mm, 512 * mm, -15 * mm, 0)},
0438 {Component::DriftCarbon, LayerStruct(1. * mm, GetDetectorMaterial("G4_C"), G4Colour(150 / 255., 75 / 255., 0), 256 * mm, 512 * mm, -15 * mm, 0)},
0439 {Component::FeeSupport, LayerStruct(2.38 * mm, GetDetectorMaterial("G4_Al"), G4Colour::Grey(), 182 * mm, 542 * mm, -67 * mm, 0)}};
0440
0441
0442 using LayerDefinition = std::tuple<Component, std::string>;
0443 const std::vector<LayerDefinition> layer_stack_phi =
0444 {
0445
0446 std::make_tuple(Component::DriftCarbon, "DriftCarbon_inner"),
0447 std::make_tuple(Component::DriftKapton, "DriftKapton_inner"),
0448 std::make_tuple(Component::DriftCuElectrode, "DriftCuElectrode_inner"),
0449 std::make_tuple(Component::Gas2, "Gas2_inner"),
0450 std::make_tuple(Component::Mesh, "Mesh_inner"),
0451 std::make_tuple(Component::Gas1, "Gas1_inner"),
0452 std::make_tuple(Component::ResistiveStrips, "ResistiveStrips_inner"),
0453 std::make_tuple(Component::KaptonStrips, "KaptonStrips_inner"),
0454 std::make_tuple(Component::CuStrips, "CuStrips_inner"),
0455 std::make_tuple(Component::PCB, "PCB_inner")};
0456
0457
0458 const std::vector<LayerDefinition> layer_stack_z =
0459 {
0460
0461 std::make_tuple(Component::PCB, "PCB_outer"),
0462 std::make_tuple(Component::CuStrips, "CuStrips_outer"),
0463 std::make_tuple(Component::KaptonStrips, "KaptonStrips_outer"),
0464 std::make_tuple(Component::ResistiveStrips, "ResistiveStrips_outer"),
0465 std::make_tuple(Component::Gas1, "Gas1_outer"),
0466 std::make_tuple(Component::Mesh, "Mesh_outer"),
0467 std::make_tuple(Component::Gas2, "Gas2_outer"),
0468 std::make_tuple(Component::DriftCuElectrode, "DriftCuElectrode_outer"),
0469 std::make_tuple(Component::DriftKapton, "DriftKapton_outer"),
0470 std::make_tuple(Component::DriftCarbon, "DriftCarbon_outer"),
0471
0472
0473 std::make_tuple(Component::FeeSupport, "FEE_support")};
0474
0475 const bool is_z = (segmentation_type == MicromegasDefs::SegmentationType::SEGMENTATION_Z);
0476
0477
0478 const auto& layer_stack = is_z ? layer_stack_z : layer_stack_phi;
0479
0480
0481 std::array<G4LogicalVolume*, 2> fee_board_logic =
0482 {
0483 is_z ? construct_fee_board(0) : nullptr,
0484 is_z ? construct_fee_board(1) : nullptr};
0485
0486 const double fee_thickness = is_z ? static_cast<G4Box*>(fee_board_logic[0]->GetSolid())->GetXHalfLength() * 2 : 0;
0487
0488
0489 double tile_thickness = std::accumulate(
0490 layer_stack.begin(), layer_stack.end(), 0.,
0491 [&layer_map](double value, const LayerDefinition& layer)
0492 { return value + layer_map.at(std::get<0>(layer)).m_thickness; });
0493
0494
0495 if (is_z)
0496 {
0497 tile_thickness += fee_thickness;
0498 }
0499
0500
0501 const double tile_dy = layer_map.at(Component::PCB).m_dy;
0502 const double tile_dz = layer_map.at(Component::PCB).m_dz;
0503
0504
0505 auto *rc = recoConsts::instance();
0506 auto *world_material = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
0507
0508
0509 const auto tilename = GetName() + "_tile_" + std::to_string(tileid) + (is_z ? "_z" : "_phi");
0510
0511 auto *tile_solid = new G4Box(tilename + "_solid", tile_thickness / 2, tile_dy / 2, tile_dz / 2);
0512 auto *tile_logic = new G4LogicalVolume(tile_solid, world_material, "invisible_" + tilename + "_logic");
0513 GetDisplayAction()->AddVolume(tile_logic, G4Colour::Grey());
0514
0515
0516 auto current_radius_local = -tile_thickness / 2;
0517 for (const auto& [type, name] : layer_stack)
0518 {
0519
0520
0521
0522
0523
0524 const G4String cname = (type == Component::Gas2) ? "micromegas_measurement_" + name : G4String(GetName()) + "_" + name;
0525
0526
0527 const auto& component(layer_map.at(type));
0528 const auto& thickness = component.m_thickness;
0529 const auto& material = component.m_material;
0530 const auto& color = component.m_color;
0531
0532 const auto& dy = component.m_dy;
0533 const auto& dz = component.m_dz;
0534
0535 const auto& y_offset = component.m_y_offset;
0536 const auto& z_offset = component.m_z_offset;
0537
0538 auto *component_solid = new G4Box(cname + "_solid", thickness / 2, dy / 2, dz / 2);
0539 auto *component_logic = new G4LogicalVolume(component_solid, material, cname + "_logic");
0540 GetDisplayAction()->AddVolume(component_logic, color);
0541
0542 const G4ThreeVector center((current_radius_local + thickness / 2), y_offset, z_offset);
0543 auto *component_phys = new G4PVPlacement(nullptr, center, component_logic, cname + "_phys", tile_logic, false, 0, OverlapCheck());
0544
0545 if (type == Component::Gas2)
0546 {
0547
0548
0549 const int layer_index = is_z ? m_FirstLayer + 1 : m_FirstLayer;
0550 m_activeVolumes.insert(std::make_pair(component_phys, layer_index));
0551 m_tiles_map.insert(std::make_pair(component_phys, tileid));
0552
0553
0554 m_layer_radius.insert(std::make_pair(layer_index, (current_radius_local + thickness / 2) / cm));
0555 m_layer_thickness.insert(std::make_pair(layer_index, thickness / cm));
0556 }
0557 else
0558 {
0559 m_passiveVolumes.insert(component_phys);
0560 }
0561
0562
0563 current_radius_local += thickness;
0564 }
0565
0566 if (is_z)
0567 {
0568
0569
0570 static constexpr double fee_y_offset = (316. / 2 - 44.7 - 141.5 / 2) * mm;
0571 static constexpr double fee_x_offset = (542. / 2 - 113.1 - 140. / 2) * mm;
0572 new G4PVPlacement(nullptr, {current_radius_local + fee_thickness / 2, -fee_y_offset, -fee_x_offset}, fee_board_logic[0], GetName() + "_fee_0_phys", tile_logic, false, 0, OverlapCheck());
0573 new G4PVPlacement(nullptr, {current_radius_local + fee_thickness / 2, -fee_y_offset, fee_x_offset}, fee_board_logic[1], GetName() + "_fee_1_phys", tile_logic, false, 0, OverlapCheck());
0574 }
0575
0576
0577 return tile_logic;
0578 }
0579
0580
0581 G4LogicalVolume* PHG4MicromegasDetector::construct_fee_board(int id)
0582 {
0583
0584 struct LayerStruct
0585 {
0586
0587 LayerStruct(const std::string& name, float thickness, G4Material* material, const G4Colour& color)
0588 : m_name(name)
0589 , m_thickness(thickness)
0590 , m_material(material)
0591 , m_color(color)
0592 {
0593 }
0594
0595
0596
0597 std::string m_name;
0598
0599
0600 float m_thickness = 0;
0601
0602
0603 G4Material* m_material = nullptr;
0604
0605
0606 G4Colour m_color = 0;
0607
0608 };
0609
0610 static constexpr double inch_to_cm = 2.54;
0611
0612
0613
0614
0615
0616
0617 const std::vector<LayerStruct> layer_stack = {
0618 LayerStruct("fee_pcb", 0.07 * inch_to_cm * cm, GetDetectorMaterial("mmg_FR4"), G4Colour::Green()),
0619 LayerStruct("fee_cu", 35e-4 * 10 * 0.8 * cm, GetDetectorMaterial("G4_Cu"), G4Colour::Brown()),
0620 LayerStruct("fee_al", 0.25 * inch_to_cm * cm, GetDetectorMaterial("G4_Al"), G4Colour::Grey())};
0621
0622
0623 const double fee_thickness = std::accumulate(
0624 layer_stack.begin(), layer_stack.end(), 0.,
0625 [](double value, const LayerStruct& layer)
0626 { return value + layer.m_thickness; });
0627
0628
0629 const double fee_dy = 141.51 * mm;
0630 const double fee_dz = 140 * mm;
0631
0632
0633 auto *rc = recoConsts::instance();
0634 auto *world_material = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
0635
0636
0637 const auto feename = GetName() + "_fee_" + std::to_string(id);
0638
0639 auto *fee_solid = new G4Box(feename + "_solid", fee_thickness / 2, fee_dy / 2, fee_dz / 2);
0640 auto *fee_logic = new G4LogicalVolume(fee_solid, world_material, "invisible_" + feename + "_logic");
0641 GetDisplayAction()->AddVolume(fee_logic, G4Colour::Grey());
0642
0643
0644 auto current_radius_local = -fee_thickness / 2;
0645 for (const auto& layer : layer_stack)
0646 {
0647
0648
0649
0650
0651
0652 const G4String cname = G4String(GetName()) + "_" + layer.m_name;
0653
0654
0655 const auto& thickness = layer.m_thickness;
0656 const auto& material = layer.m_material;
0657 const auto& color = layer.m_color;
0658
0659 auto *component_solid = new G4Box(cname + "_solid", thickness / 2, fee_dy / 2, fee_dz / 2);
0660 auto *component_logic = new G4LogicalVolume(component_solid, material, cname + "_logic");
0661 GetDisplayAction()->AddVolume(component_logic, color);
0662
0663 const G4ThreeVector center((current_radius_local + thickness / 2), 0, 0);
0664 auto *component_phys = new G4PVPlacement(nullptr, center, component_logic, cname + "_phys", fee_logic, false, 0, OverlapCheck());
0665
0666
0667 m_passiveVolumes.insert(component_phys);
0668
0669
0670 current_radius_local += thickness;
0671 }
0672
0673
0674 return fee_logic;
0675 }
0676
0677
0678 void PHG4MicromegasDetector::add_geometry_node()
0679 {
0680
0681 if (!m_Params->get_int_param("active"))
0682 {
0683 return;
0684 }
0685
0686
0687 const auto geonode_name = std::string("CYLINDERGEOM_") + m_SuperDetector + "_FULL";
0688 auto *geonode = findNode::getClass<PHG4CylinderGeomContainer>(topNode(), geonode_name);
0689 if (!geonode)
0690 {
0691 geonode = new PHG4CylinderGeomContainer;
0692 PHNodeIterator iter(topNode());
0693 auto *runNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "RUN"));
0694 PHNodeIterator runiter(runNode);
0695 PHCompositeNode *geomNode = dynamic_cast<PHCompositeNode *>(runiter.findFirst("PHCompositeNode", "RECO_TRACKING_GEOMETRY"));
0696 if(!geomNode)
0697 {
0698 geomNode = new PHCompositeNode("RECO_TRACKING_GEOMETRY");
0699 runNode->addNode(geomNode);
0700 }
0701 auto *newNode = new PHIODataNode<PHObject>(geonode, geonode_name, "PHObject");
0702 geomNode->addNode(newNode);
0703 }
0704
0705
0706 static constexpr double length = 220;
0707
0708
0709
0710 bool is_first = true;
0711 for (const auto& [layer_index, radius] : m_layer_radius)
0712 {
0713
0714
0715 auto *cylinder = new CylinderGeomMicromegas(layer_index);
0716 cylinder->set_radius(radius);
0717 cylinder->set_thickness(m_layer_thickness.at(layer_index));
0718 cylinder->set_zmin(-length / 2);
0719 cylinder->set_zmax(length / 2);
0720
0721
0722 cylinder->set_tiles(m_tiles);
0723
0724
0725
0726
0727
0728 cylinder->set_segmentation_type(is_first ? MicromegasDefs::SegmentationType::SEGMENTATION_PHI : MicromegasDefs::SegmentationType::SEGMENTATION_Z);
0729
0730
0731
0732
0733
0734
0735 cylinder->set_drift_direction(is_first ? MicromegasDefs::DriftDirection::OUTWARD : MicromegasDefs::DriftDirection::INWARD);
0736
0737
0738
0739 cylinder->set_pitch(is_first ? 0.1 : 0.2);
0740
0741
0742 {
0743 cylinder->identify(std::cout);
0744 }
0745
0746 geonode->AddLayerGeom(layer_index, cylinder);
0747
0748 is_first = false;
0749 }
0750 }