File indexing completed on 2025-08-06 08:18:55
0001 #include "PHG4CEmcTestBeamDetector.h"
0002
0003 #include <g4main/PHG4Detector.h> // for PHG4Detector
0004
0005 #include <phool/recoConsts.h>
0006
0007 #include <Geant4/G4Box.hh>
0008 #include <Geant4/G4Colour.hh>
0009 #include <Geant4/G4LogicalVolume.hh>
0010 #include <Geant4/G4PVPlacement.hh>
0011 #include <Geant4/G4RotationMatrix.hh> // for G4RotationMatrix
0012 #include <Geant4/G4String.hh> // for G4String
0013 #include <Geant4/G4SystemOfUnits.hh>
0014 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
0015 #include <Geant4/G4Transform3D.hh> // for G4Transform3D
0016 #include <Geant4/G4Tubs.hh>
0017 #include <Geant4/G4Types.hh> // for G4double
0018 #include <Geant4/G4VisAttributes.hh>
0019
0020 #include <algorithm> // for copy
0021 #include <cmath> // for cos, sin, NAN, acos, atan
0022 #include <iostream> // for operator<<, ostringstream
0023 #include <sstream>
0024
0025 class G4Material;
0026 class G4VSolid;
0027 class PHCompositeNode;
0028
0029 using namespace std;
0030
0031 static double no_overlap = 0.0001 * cm;
0032
0033 PHG4CEmcTestBeamDetector::PHG4CEmcTestBeamDetector(PHG4Subsystem* subsys, PHCompositeNode* Node, const std::string& dnam, const int lyr)
0034 : PHG4Detector(subsys, Node, dnam)
0035 , gap(0.25 * mm)
0036 , place_in_x(0 * cm)
0037 , place_in_y(0 * cm)
0038 , place_in_z(0 * cm)
0039 , plate_x(135 * mm)
0040 , plate_z(135 * mm)
0041 , x_rot(0)
0042 , y_rot(0)
0043 , z_rot(0)
0044 , alpha(NAN)
0045 , inner_radius(NAN)
0046 , outer_radius(NAN)
0047 , tower_angular_coverage(NAN)
0048 , cemc_angular_coverage(NAN)
0049 , active_scinti_fraction(0.78)
0050 , sandwiches_per_tower(12)
0051 ,
0052 num_towers(7)
0053 , active(0)
0054 , absorberactive(0)
0055 , layer(lyr)
0056 , blackhole(0)
0057 {
0058 w_dimension[0] = plate_x;
0059 w_dimension[1] = 0.5 * mm;
0060 w_dimension[2] = plate_z;
0061 sc_dimension[0] = plate_x;
0062 sc_dimension[1] = 1 * mm;
0063 sc_dimension[2] = plate_z;
0064 sandwich_thickness = 2 * w_dimension[1] + sc_dimension[1];
0065 for (int i = 0; i < 4; i++)
0066 {
0067 sandwich_vol.push_back(nullptr);
0068 }
0069 }
0070
0071
0072
0073 int PHG4CEmcTestBeamDetector::IsInCEmcTestBeam(G4VPhysicalVolume* volume) const
0074 {
0075 if (active && volume == sandwich_vol[2])
0076 {
0077 return 1;
0078 }
0079 if (absorberactive && (volume == sandwich_vol[0] || volume == sandwich_vol[1]))
0080 {
0081 return -1;
0082 }
0083 if (absorberactive && sandwich_vol[3] && volume == sandwich_vol[3])
0084 {
0085 return -1;
0086 }
0087 return 0;
0088 }
0089
0090 void PHG4CEmcTestBeamDetector::ConstructMe(G4LogicalVolume* logicWorld)
0091 {
0092 CalculateGeometry();
0093 recoConsts* rc = recoConsts::instance();
0094 G4Material* Air = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
0095 G4VSolid* cemc_tub = new G4Tubs("CEmcTub", inner_radius - 2 * no_overlap, outer_radius + 2 * no_overlap, (w_dimension[2] + 2 * no_overlap) / 2., 0, cemc_angular_coverage);
0096 G4LogicalVolume* cemc_log = new G4LogicalVolume(cemc_tub, Air, G4String("CEmc"), nullptr, nullptr, nullptr);
0097
0098 G4RotationMatrix cemc_rotm;
0099
0100 double radius_at_center = inner_radius + (outer_radius - inner_radius) / 2.;
0101 double xcenter = radius_at_center * cos(cemc_angular_coverage / 2.);
0102 double ycenter = radius_at_center * sin(cemc_angular_coverage / 2.);
0103 cemc_rotm.rotateX(x_rot);
0104 cemc_rotm.rotateY(y_rot);
0105 cemc_rotm.rotateZ(z_rot);
0106 new G4PVPlacement(G4Transform3D(cemc_rotm, G4ThreeVector(place_in_x - xcenter, place_in_y - ycenter, place_in_z)), cemc_log, "CEmc", logicWorld, false, false, OverlapCheck());
0107 G4VSolid* tower_tub = new G4Tubs("TowerTub", inner_radius - no_overlap, outer_radius + no_overlap, (w_dimension[2] + no_overlap) / 2., 0, tower_angular_coverage);
0108 G4LogicalVolume* tower_log = new G4LogicalVolume(tower_tub, Air, G4String("CEmcTower"), nullptr, nullptr, nullptr);
0109
0110
0111
0112
0113
0114
0115 ostringstream tower_vol_name;
0116 for (int i = 0; i < 7; i++)
0117 {
0118 tower_vol_name << "CEmcTower_" << i;
0119 double phi = -i * tower_angular_coverage;
0120 G4RotationMatrix* tower_rotm = new G4RotationMatrix();
0121 tower_rotm->rotateZ(phi * rad);
0122 new G4PVPlacement(tower_rotm, G4ThreeVector(0, 0, 0), tower_log, tower_vol_name.str(), cemc_log, false, i, OverlapCheck());
0123 tower_vol_name.str("");
0124 }
0125 ConstructTowerVolume(tower_log);
0126 return;
0127 }
0128
0129
0130 int PHG4CEmcTestBeamDetector::ConstructTowerVolume(G4LogicalVolume* tower_log)
0131 {
0132 recoConsts* rc = recoConsts::instance();
0133 G4Material* Air = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
0134 G4VSolid* sandwich_box = new G4Box("Sandwich_box",
0135 w_dimension[0] / 2., sandwich_thickness / 2., w_dimension[2] / 2.);
0136
0137 G4LogicalVolume* sandwich_log = new G4LogicalVolume(sandwich_box,
0138 Air,
0139 G4String("CEmcSandwich"),
0140 nullptr, nullptr, nullptr);
0141 G4VisAttributes* sandwichVisAtt = new G4VisAttributes();
0142 sandwichVisAtt->SetVisibility(true);
0143 sandwichVisAtt->SetForceSolid(true);
0144 sandwichVisAtt->SetColour(G4Colour::White());
0145 sandwich_log->SetVisAttributes(sandwichVisAtt);
0146 ostringstream sandwich_name;
0147 for (int i = 0; i < 12; i++)
0148 {
0149 G4RotationMatrix* sandwich_rotm = new G4RotationMatrix();
0150 double phi = -i * alpha;
0151 sandwich_rotm->rotateZ(phi * rad);
0152 sandwich_name << "CEmcSandwich_" << i;
0153 double xshift = cos(phi) * (inner_radius + (outer_radius - inner_radius) / 2.);
0154 double yshift = -sin(phi) * (inner_radius + (outer_radius - inner_radius) / 2.);
0155
0156
0157 double xcorr = atan(phi) * sandwich_thickness / 2.;
0158 double ycorr = sandwich_thickness / 2.;
0159
0160 new G4PVPlacement(sandwich_rotm, G4ThreeVector(xshift + xcorr, yshift + ycorr, 0),
0161 sandwich_log,
0162 sandwich_name.str(),
0163 tower_log, false, i, OverlapCheck());
0164 sandwich_name.str("");
0165 }
0166 ConstructSandwichVolume(sandwich_log);
0167 return 0;
0168 }
0169
0170
0171 int PHG4CEmcTestBeamDetector::ConstructSandwichVolume(G4LogicalVolume* sandwich)
0172 {
0173 vector<G4LogicalVolume*> block_logic;
0174 G4Material* AbsorberMaterial = GetDetectorMaterial("G4_W");
0175 G4Material* ScintiMaterial = GetDetectorMaterial("G4_POLYSTYRENE");
0176
0177 if (active_scinti_fraction > 1 || active_scinti_fraction < 0)
0178 {
0179 cout << "invalid active scintillator fraction " << active_scinti_fraction
0180 << " try between 0 and 1" << endl;
0181 }
0182
0183 double sc_active_thickness = sc_dimension[1] * active_scinti_fraction;
0184 double sc_passive_thickness = sc_dimension[1] - sc_active_thickness;
0185
0186 G4VSolid* block_w = new G4Box("Tungsten_box",
0187 w_dimension[0] / 2., w_dimension[1] / 2., w_dimension[2] / 2.);
0188 G4VSolid* block_sc = new G4Box("Scinti_box",
0189 sc_dimension[0] / 2., sc_active_thickness / 2., sc_dimension[2] / 2.);
0190 G4VSolid* block_passive_sc = nullptr;
0191 block_logic.push_back(new G4LogicalVolume(block_w,
0192 AbsorberMaterial,
0193 "Plate_log_W",
0194 nullptr, nullptr, nullptr));
0195 block_logic.push_back(new G4LogicalVolume(block_sc,
0196 ScintiMaterial,
0197 "Plate_log_Sc",
0198 nullptr, nullptr, nullptr));
0199 G4VisAttributes* matVis = new G4VisAttributes();
0200 G4VisAttributes* matVis1 = new G4VisAttributes();
0201 matVis->SetVisibility(true);
0202 matVis->SetForceSolid(true);
0203 matVis->SetColour(G4Colour::Red());
0204 matVis1->SetVisibility(true);
0205 matVis1->SetForceSolid(true);
0206 matVis1->SetColour(G4Colour::Green());
0207 block_logic[0]->SetVisAttributes(matVis);
0208 block_logic[1]->SetVisAttributes(matVis1);
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220 sandwich_vol[0] = new G4PVPlacement(nullptr, G4ThreeVector(0, -(w_dimension[1] + sc_dimension[1]) / 2., 0),
0221 block_logic[0],
0222 "CEmc_W_plate_down",
0223 sandwich, false, 0, OverlapCheck());
0224
0225
0226
0227 sandwich_vol[1] = new G4PVPlacement(nullptr, G4ThreeVector(0, (w_dimension[1] + sc_dimension[1]) / 2., 0),
0228 block_logic[0],
0229 "CEmc_W_plate_up",
0230 sandwich, false, 0, OverlapCheck());
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240 sandwich_vol[2] = new G4PVPlacement(nullptr, G4ThreeVector(0, -sc_passive_thickness / 2., 0),
0241 block_logic[1],
0242 "CEmc_Scinti_plate",
0243 sandwich, false, 0, OverlapCheck());
0244
0245 if (sc_passive_thickness > 0)
0246 {
0247 G4VisAttributes* matVis2 = new G4VisAttributes();
0248 matVis1->SetVisibility(true);
0249 matVis1->SetForceSolid(true);
0250 matVis1->SetColour(G4Colour::Blue());
0251 block_passive_sc = new G4Box("Passive_Scinti_box",
0252 sc_dimension[0] / 2., sc_passive_thickness / 2., sc_dimension[2] / 2.);
0253 block_logic.push_back(new G4LogicalVolume(block_passive_sc,
0254 ScintiMaterial,
0255 "Plate_log_Passive_Sc",
0256 nullptr, nullptr, nullptr));
0257 block_logic[2]->SetVisAttributes(matVis2);
0258
0259
0260
0261 sandwich_vol[3] = new G4PVPlacement(nullptr, G4ThreeVector(0, sc_active_thickness / 2., 0),
0262 block_logic[2],
0263 "CEmc_Passive_Si_plate",
0264 sandwich, false, 0, OverlapCheck());
0265 }
0266 else
0267 {
0268 sandwich_vol[3] = nullptr;
0269 }
0270 return 0;
0271 }
0272
0273 void PHG4CEmcTestBeamDetector::CalculateGeometry()
0274 {
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284 alpha = acos(1 - (gap * gap) / (2 * plate_x * plate_x));
0285
0286 inner_radius = sandwich_thickness / tan(alpha);
0287 outer_radius = sqrt((inner_radius + plate_x) * (inner_radius + plate_x) + sandwich_thickness * sandwich_thickness);
0288
0289
0290
0291 tower_angular_coverage = sandwiches_per_tower * alpha + 0.00005 * deg;
0292
0293 cemc_angular_coverage = num_towers * tower_angular_coverage;
0294 return;
0295 }