File indexing completed on 2025-01-31 09:22:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include "DetectorConstruction.hh"
0031
0032 #include "CellParameterisation.hh"
0033 #include "Constants.hh"
0034 #include "DriftChamberSD.hh"
0035 #include "EmCalorimeterSD.hh"
0036 #include "HadCalorimeterSD.hh"
0037 #include "HodoscopeSD.hh"
0038 #include "MagneticField.hh"
0039
0040 #include "G4Box.hh"
0041 #include "G4Colour.hh"
0042 #include "G4FieldManager.hh"
0043 #include "G4GenericMessenger.hh"
0044 #include "G4LogicalVolume.hh"
0045 #include "G4Material.hh"
0046 #include "G4NistManager.hh"
0047 #include "G4PVParameterised.hh"
0048 #include "G4PVPlacement.hh"
0049 #include "G4PVReplica.hh"
0050 #include "G4RotationMatrix.hh"
0051 #include "G4RunManager.hh"
0052 #include "G4SDManager.hh"
0053 #include "G4SystemOfUnits.hh"
0054 #include "G4ThreeVector.hh"
0055 #include "G4Tubs.hh"
0056 #include "G4UserLimits.hh"
0057 #include "G4VisAttributes.hh"
0058
0059 namespace B5
0060 {
0061
0062
0063
0064 G4ThreadLocal MagneticField* DetectorConstruction::fMagneticField = nullptr;
0065 G4ThreadLocal G4FieldManager* DetectorConstruction::fFieldMgr = nullptr;
0066
0067
0068
0069 DetectorConstruction::DetectorConstruction()
0070 {
0071 fArmRotation = new G4RotationMatrix();
0072 fArmRotation->rotateY(fArmAngle);
0073
0074
0075 DefineCommands();
0076 }
0077
0078
0079
0080 DetectorConstruction::~DetectorConstruction()
0081 {
0082 delete fArmRotation;
0083 delete fMessenger;
0084 }
0085
0086
0087
0088 G4VPhysicalVolume* DetectorConstruction::Construct()
0089 {
0090
0091 ConstructMaterials();
0092 auto air = G4Material::GetMaterial("G4_AIR");
0093
0094 auto argonGas = G4Material::GetMaterial("G4_Ar");
0095 auto scintillator = G4Material::GetMaterial("G4_PLASTIC_SC_VINYLTOLUENE");
0096 auto csI = G4Material::GetMaterial("G4_CESIUM_IODIDE");
0097 auto lead = G4Material::GetMaterial("G4_Pb");
0098
0099
0100
0101 G4bool checkOverlaps = true;
0102
0103
0104
0105 auto worldSolid = new G4Box("worldBox", 10. * m, 3. * m, 10. * m);
0106 auto worldLogical = new G4LogicalVolume(worldSolid, air, "worldLogical");
0107 auto worldPhysical = new G4PVPlacement(nullptr, G4ThreeVector(), worldLogical, "worldPhysical",
0108 nullptr, false, 0, checkOverlaps);
0109
0110
0111
0112 auto magneticSolid = new G4Tubs("magneticTubs", 0., 1. * m, 1. * m, 0., 360. * deg);
0113
0114 fMagneticLogical = new G4LogicalVolume(magneticSolid, air, "magneticLogical");
0115
0116
0117
0118 auto fieldRot = new G4RotationMatrix();
0119 fieldRot->rotateX(90. * deg);
0120 new G4PVPlacement(fieldRot, G4ThreeVector(), fMagneticLogical, "magneticPhysical", worldLogical,
0121 false, 0, checkOverlaps);
0122
0123
0124 auto userLimits = new G4UserLimits(1 * m);
0125 fMagneticLogical->SetUserLimits(userLimits);
0126
0127
0128 auto firstArmSolid = new G4Box("firstArmBox", 1.5 * m, 1. * m, 3. * m);
0129 auto firstArmLogical = new G4LogicalVolume(firstArmSolid, air, "firstArmLogical");
0130 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., -5. * m), firstArmLogical, "firstArmPhysical",
0131 worldLogical, false, 0, checkOverlaps);
0132
0133
0134 auto secondArmSolid = new G4Box("secondArmBox", 2. * m, 2. * m, 3.5 * m);
0135 auto secondArmLogical = new G4LogicalVolume(secondArmSolid, air, "secondArmLogical");
0136 auto x = -5. * m * std::sin(fArmAngle);
0137 auto z = 5. * m * std::cos(fArmAngle);
0138 fSecondArmPhys = new G4PVPlacement(fArmRotation, G4ThreeVector(x, 0., z), secondArmLogical,
0139 "fSecondArmPhys", worldLogical, false, 0, checkOverlaps);
0140
0141
0142 auto hodoscope1Solid = new G4Box("hodoscope1Box", 5. * cm, 20. * cm, 0.5 * cm);
0143 fHodoscope1Logical = new G4LogicalVolume(hodoscope1Solid, scintillator, "hodoscope1Logical");
0144
0145 for (auto i = 0; i < kNofHodoscopes1; i++) {
0146 G4double x1 = (i - kNofHodoscopes1 / 2) * 10. * cm;
0147 new G4PVPlacement(nullptr, G4ThreeVector(x1, 0., -1.5 * m), fHodoscope1Logical,
0148 "hodoscope1Physical", firstArmLogical, false, i, checkOverlaps);
0149 }
0150
0151
0152 auto chamber1Solid = new G4Box("chamber1Box", 1. * m, 30. * cm, 1. * cm);
0153 auto chamber1Logical = new G4LogicalVolume(chamber1Solid, argonGas, "chamber1Logical");
0154
0155 for (auto i = 0; i < kNofChambers; i++) {
0156 G4double z1 = (i - kNofChambers / 2) * 0.5 * m;
0157 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., z1), chamber1Logical, "chamber1Physical",
0158 firstArmLogical, false, i, checkOverlaps);
0159 }
0160
0161
0162 auto wirePlane1Solid = new G4Box("wirePlane1Box", 1. * m, 30. * cm, 0.1 * mm);
0163 fWirePlane1Logical = new G4LogicalVolume(wirePlane1Solid, argonGas, "wirePlane1Logical");
0164 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., 0.), fWirePlane1Logical, "wirePlane1Physical",
0165 chamber1Logical, false, 0, checkOverlaps);
0166
0167
0168 auto hodoscope2Solid = new G4Box("hodoscope2Box", 5. * cm, 20. * cm, 0.5 * cm);
0169 fHodoscope2Logical = new G4LogicalVolume(hodoscope2Solid, scintillator, "hodoscope2Logical");
0170
0171 for (auto i = 0; i < kNofHodoscopes2; i++) {
0172 G4double x2 = (i - kNofHodoscopes2 / 2) * 10. * cm;
0173 new G4PVPlacement(nullptr, G4ThreeVector(x2, 0., 0.), fHodoscope2Logical, "hodoscope2Physical",
0174 secondArmLogical, false, i, checkOverlaps);
0175 }
0176
0177
0178 auto chamber2Solid = new G4Box("chamber2Box", 1.5 * m, 30. * cm, 1. * cm);
0179 auto chamber2Logical = new G4LogicalVolume(chamber2Solid, argonGas, "chamber2Logical");
0180
0181 for (auto i = 0; i < kNofChambers; i++) {
0182 G4double z2 = (i - kNofChambers / 2) * 0.5 * m - 1.5 * m;
0183 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., z2), chamber2Logical, "chamber2Physical",
0184 secondArmLogical, false, i, checkOverlaps);
0185 }
0186
0187
0188 auto wirePlane2Solid = new G4Box("wirePlane2Box", 1.5 * m, 30. * cm, 0.1 * mm);
0189 fWirePlane2Logical = new G4LogicalVolume(wirePlane2Solid, argonGas, "wirePlane2Logical");
0190 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., 0.), fWirePlane2Logical, "wirePlane2Physical",
0191 chamber2Logical, false, 0, checkOverlaps);
0192
0193
0194 auto emCalorimeterSolid = new G4Box("EMcalorimeterBox", 1.5 * m, 30. * cm, 15. * cm);
0195 auto emCalorimeterLogical = new G4LogicalVolume(emCalorimeterSolid, csI, "EMcalorimeterLogical");
0196 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., 2. * m), emCalorimeterLogical,
0197 "EMcalorimeterPhysical", secondArmLogical, false, 0, checkOverlaps);
0198
0199
0200 auto cellSolid = new G4Box("cellBox", 7.5 * cm, 7.5 * cm, 15. * cm);
0201 fCellLogical = new G4LogicalVolume(cellSolid, csI, "cellLogical");
0202 G4VPVParameterisation* cellParam = new CellParameterisation();
0203 new G4PVParameterised("cellPhysical", fCellLogical, emCalorimeterLogical, kXAxis, kNofEmCells,
0204 cellParam);
0205
0206
0207 auto hadCalorimeterSolid = new G4Box("HadCalorimeterBox", 1.5 * m, 30. * cm, 50. * cm);
0208 auto hadCalorimeterLogical =
0209 new G4LogicalVolume(hadCalorimeterSolid, lead, "HadCalorimeterLogical");
0210 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., 3. * m), hadCalorimeterLogical,
0211 "HadCalorimeterPhysical", secondArmLogical, false, 0, checkOverlaps);
0212
0213
0214 auto HadCalColumnSolid = new G4Box("HadCalColumnBox", 15. * cm, 30. * cm, 50. * cm);
0215 auto HadCalColumnLogical = new G4LogicalVolume(HadCalColumnSolid, lead, "HadCalColumnLogical");
0216 new G4PVReplica("HadCalColumnPhysical", HadCalColumnLogical, hadCalorimeterLogical, kXAxis,
0217 kNofHadColumns, 30. * cm);
0218
0219
0220 auto HadCalCellSolid = new G4Box("HadCalCellBox", 15. * cm, 15. * cm, 50. * cm);
0221 auto HadCalCellLogical = new G4LogicalVolume(HadCalCellSolid, lead, "HadCalCellLogical");
0222 new G4PVReplica("HadCalCellPhysical", HadCalCellLogical, HadCalColumnLogical, kYAxis, kNofHadRows,
0223 30. * cm);
0224
0225
0226 auto HadCalLayerSolid = new G4Box("HadCalLayerBox", 15. * cm, 15. * cm, 2.5 * cm);
0227 auto HadCalLayerLogical = new G4LogicalVolume(HadCalLayerSolid, lead, "HadCalLayerLogical");
0228 new G4PVReplica("HadCalLayerPhysical", HadCalLayerLogical, HadCalCellLogical, kZAxis,
0229 kNofHadCells, 5. * cm);
0230
0231
0232 auto HadCalScintiSolid = new G4Box("HadCalScintiBox", 15. * cm, 15. * cm, 0.5 * cm);
0233 fHadCalScintiLogical =
0234 new G4LogicalVolume(HadCalScintiSolid, scintillator, "HadCalScintiLogical");
0235 new G4PVPlacement(nullptr, G4ThreeVector(0., 0., 2. * cm), fHadCalScintiLogical,
0236 "HadCalScintiPhysical", HadCalLayerLogical, false, 0, checkOverlaps);
0237
0238
0239
0240 G4VisAttributes invisible(G4VisAttributes::GetInvisible());
0241 G4VisAttributes invisibleBlue(false, G4Colour::Blue());
0242 G4VisAttributes invisibleGreen(false, G4Colour::Green());
0243 G4VisAttributes invisibleYellow(false, G4Colour::Yellow());
0244 G4VisAttributes blue(G4Colour::Blue());
0245 G4VisAttributes cgray(G4Colour::Gray());
0246 G4VisAttributes green(G4Colour::Green());
0247 G4VisAttributes red(G4Colour::Red());
0248 G4VisAttributes yellow(G4Colour::Yellow());
0249
0250 worldLogical->SetVisAttributes(invisible);
0251 firstArmLogical->SetVisAttributes(invisible);
0252 secondArmLogical->SetVisAttributes(invisible);
0253
0254 fMagneticLogical->SetVisAttributes(cgray);
0255 fHodoscope1Logical->SetVisAttributes(red);
0256 fHodoscope2Logical->SetVisAttributes(red);
0257
0258 chamber1Logical->SetVisAttributes(green);
0259 chamber2Logical->SetVisAttributes(green);
0260 fWirePlane1Logical->SetVisAttributes(invisibleGreen);
0261 fWirePlane2Logical->SetVisAttributes(invisibleGreen);
0262
0263 emCalorimeterLogical->SetVisAttributes(invisibleYellow);
0264 fCellLogical->SetVisAttributes(yellow);
0265
0266 hadCalorimeterLogical->SetVisAttributes(blue);
0267 HadCalColumnLogical->SetVisAttributes(invisibleBlue);
0268 HadCalCellLogical->SetVisAttributes(invisibleBlue);
0269 HadCalLayerLogical->SetVisAttributes(invisibleBlue);
0270 fHadCalScintiLogical->SetVisAttributes(invisibleBlue);
0271
0272
0273
0274 return worldPhysical;
0275 }
0276
0277
0278
0279 void DetectorConstruction::ConstructSDandField()
0280 {
0281
0282 auto sdManager = G4SDManager::GetSDMpointer();
0283 G4String SDname;
0284
0285 auto hodoscope1 = new HodoscopeSD(SDname = "/hodoscope1");
0286 sdManager->AddNewDetector(hodoscope1);
0287 fHodoscope1Logical->SetSensitiveDetector(hodoscope1);
0288
0289 auto hodoscope2 = new HodoscopeSD(SDname = "/hodoscope2");
0290 sdManager->AddNewDetector(hodoscope2);
0291 fHodoscope2Logical->SetSensitiveDetector(hodoscope2);
0292
0293 auto chamber1 = new DriftChamberSD(SDname = "/chamber1");
0294 sdManager->AddNewDetector(chamber1);
0295 fWirePlane1Logical->SetSensitiveDetector(chamber1);
0296
0297 auto chamber2 = new DriftChamberSD(SDname = "/chamber2");
0298 sdManager->AddNewDetector(chamber2);
0299 fWirePlane2Logical->SetSensitiveDetector(chamber2);
0300
0301 auto emCalorimeter = new EmCalorimeterSD(SDname = "/EMcalorimeter");
0302 sdManager->AddNewDetector(emCalorimeter);
0303 fCellLogical->SetSensitiveDetector(emCalorimeter);
0304
0305 auto hadCalorimeter = new HadCalorimeterSD(SDname = "/HadCalorimeter");
0306 sdManager->AddNewDetector(hadCalorimeter);
0307 fHadCalScintiLogical->SetSensitiveDetector(hadCalorimeter);
0308
0309
0310 fMagneticField = new MagneticField();
0311 fFieldMgr = new G4FieldManager();
0312 fFieldMgr->SetDetectorField(fMagneticField);
0313 fFieldMgr->CreateChordFinder(fMagneticField);
0314 G4bool forceToAllDaughters = true;
0315 fMagneticLogical->SetFieldManager(fFieldMgr, forceToAllDaughters);
0316 }
0317
0318
0319
0320 void DetectorConstruction::ConstructMaterials()
0321 {
0322 auto nistManager = G4NistManager::Instance();
0323
0324
0325 nistManager->FindOrBuildMaterial("G4_AIR");
0326
0327
0328 nistManager->FindOrBuildMaterial("G4_Ar");
0329
0330
0331
0332
0333
0334
0335
0336 nistManager->FindOrBuildMaterial("G4_PLASTIC_SC_VINYLTOLUENE");
0337
0338
0339 nistManager->FindOrBuildMaterial("G4_CESIUM_IODIDE");
0340
0341
0342 nistManager->FindOrBuildMaterial("G4_Pb");
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353 G4cout << G4endl << "The materials defined are : " << G4endl << G4endl;
0354 G4cout << *(G4Material::GetMaterialTable()) << G4endl;
0355 }
0356
0357
0358
0359 void DetectorConstruction::SetArmAngle(G4double val)
0360 {
0361 if (!fSecondArmPhys) {
0362 G4cerr << "Detector has not yet been constructed." << G4endl;
0363 return;
0364 }
0365
0366 fArmAngle = val;
0367 *fArmRotation = G4RotationMatrix();
0368 fArmRotation->rotateY(fArmAngle);
0369 auto x = -5. * m * std::sin(fArmAngle);
0370 auto z = 5. * m * std::cos(fArmAngle);
0371 fSecondArmPhys->SetTranslation(G4ThreeVector(x, 0., z));
0372
0373
0374 G4RunManager::GetRunManager()->GeometryHasBeenModified();
0375 }
0376
0377
0378
0379 void DetectorConstruction::DefineCommands()
0380 {
0381
0382 fMessenger = new G4GenericMessenger(this, "/B5/detector/", "Detector control");
0383
0384
0385 auto& armAngleCmd = fMessenger->DeclareMethodWithUnit(
0386 "armAngle", "deg", &DetectorConstruction::SetArmAngle, "Set rotation angle of the second arm.");
0387 armAngleCmd.SetParameterName("angle", true);
0388 armAngleCmd.SetRange("angle>=0. && angle<180.");
0389 armAngleCmd.SetDefaultValue("30.");
0390 }
0391
0392
0393
0394 }