File indexing completed on 2026-09-21 08:30:08
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
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #include "DetectorConstruction.hh"
0044
0045 #include "CheckVolumeSD.hh"
0046 #include "DetectorMessenger.hh"
0047 #include "PhantomSD.hh"
0048 #include "TargetSD.hh"
0049
0050 #include "G4Box.hh"
0051 #include "G4Colour.hh"
0052 #include "G4GeometryManager.hh"
0053 #include "G4LogicalVolume.hh"
0054 #include "G4LogicalVolumeStore.hh"
0055 #include "G4Material.hh"
0056 #include "G4NistManager.hh"
0057 #include "G4PVPlacement.hh"
0058 #include "G4PhysicalConstants.hh"
0059 #include "G4PhysicalVolumeStore.hh"
0060 #include "G4RunManager.hh"
0061 #include "G4SDManager.hh"
0062 #include "G4SolidStore.hh"
0063 #include "G4SystemOfUnits.hh"
0064 #include "G4Tubs.hh"
0065 #include "G4VPhysicalVolume.hh"
0066 #include "G4VisAttributes.hh"
0067 #include "G4ios.hh"
0068 #include "globals.hh"
0069
0070
0071
0072 DetectorConstruction::DetectorConstruction()
0073 {
0074 fLogicTarget1 = 0;
0075 fLogicTarget2 = 0;
0076
0077 fMessenger = new DetectorMessenger(this);
0078 fVerbose = false;
0079
0080 fNumZ = 60;
0081 fNumR = 80;
0082
0083 fNumE = 200;
0084 fMaxEnergy = 50.0 * MeV;
0085
0086 fDistanceVacuumTarget = 30. * mm,
0087
0088 fDelta = 0.001 * mm;
0089
0090 fTargetRadius = 100. * mm;
0091 fTarget1Z = 9. * mm;
0092 fTarget2Z = 6. * mm;
0093
0094 fGasVolumeRadius = 210. * mm;
0095 fGasVolumeZ = 690. * mm;
0096 fMylarVolumeZ = 0.02 * mm;
0097
0098 fCheckVolumeZ = 0.1 * mm;
0099 fCheckShiftZ = 200. * mm;
0100
0101 fAbsorberRadius = 200. * mm;
0102 fPhantomRadius = 300. * mm;
0103 fPhantomZ = 300. * mm;
0104
0105 fAirZ = 210. * mm;
0106 fAbsorberShiftZ = 70. * mm;
0107 fWindowZ = 0.05 * mm;
0108
0109 G4NistManager* man = G4NistManager::Instance();
0110
0111
0112 fTarget1Material = man->FindOrBuildMaterial("G4_Be");
0113 fWindowMaterial = fTarget1Material;
0114 fTarget2Material = man->FindOrBuildMaterial("G4_W");
0115 fLightMaterial = man->FindOrBuildMaterial("G4_He");
0116 fAbsorberMaterial = man->FindOrBuildMaterial("G4_WATER");
0117 fWorldMaterial = man->FindOrBuildMaterial("G4_AIR");
0118 fMylar = man->FindOrBuildMaterial("G4_MYLAR");
0119
0120 G4cout << *(G4Material::GetMaterialTable()) << G4endl;
0121 }
0122
0123
0124
0125 DetectorConstruction::~DetectorConstruction()
0126 {
0127 delete fMessenger;
0128 }
0129
0130
0131
0132 void DetectorConstruction::InitialiseGeometryParameters()
0133 {
0134
0135
0136 G4double factor = 1.2;
0137
0138 fWorldXY = factor * std::max(fPhantomRadius, fGasVolumeRadius);
0139 fAbsorberZ = fPhantomZ / fNumZ;
0140 fGasVolumeZ = 1000. * mm - fAbsorberShiftZ - fAirZ - fTarget1Z - fTarget2Z;
0141
0142 G4double ztot = fGasVolumeZ + fAirZ + fPhantomZ + fDistanceVacuumTarget;
0143 fTargetVolumeZ = fDistanceVacuumTarget + fTarget2Z + fTarget1Z + fDelta;
0144 fWorldZ = factor * ztot * 0.5;
0145
0146 if (fCheckShiftZ < fDelta) {
0147 fCheckShiftZ = fDelta;
0148 }
0149 if (fCheckShiftZ > fAirZ - fCheckVolumeZ - fDelta) {
0150 fCheckShiftZ = fAirZ - fCheckVolumeZ - fDelta;
0151 }
0152
0153
0154
0155 fWindowPosZ = -(ztot + fWindowZ) * 0.5;
0156 fGeneratorPosZ = fWindowPosZ - 0.5 * fWindowZ - fDelta;
0157
0158 fTargetVolumePosZ = -0.5 * (ztot - fTargetVolumeZ);
0159 fTarget1PosZ = -0.5 * (fTargetVolumeZ - fTarget1Z) + fDistanceVacuumTarget;
0160 fTarget2PosZ = fTarget1PosZ + 0.5 * (fTarget2Z + fTarget1Z);
0161
0162 fGasVolumePosZ = fTargetVolumePosZ + 0.5 * (fTargetVolumeZ + fGasVolumeZ);
0163 fCheckVolumePosZ = fGasVolumePosZ + 0.5 * (fGasVolumeZ + fCheckVolumeZ) + fCheckShiftZ;
0164 fMylarPosZ = fGasVolumePosZ + 0.5 * (fGasVolumeZ + fMylarVolumeZ) + fDelta;
0165
0166 fPhantomPosZ = fGasVolumePosZ + 0.5 * (fGasVolumeZ + fPhantomZ) + fAirZ;
0167 fAbsorberPosZ = fAbsorberShiftZ - 0.5 * (fPhantomZ - fAbsorberZ);
0168
0169 fShiftZPh = fPhantomPosZ - 0.5 * fPhantomZ;
0170
0171 DumpGeometryParameters();
0172 }
0173
0174
0175
0176 G4VPhysicalVolume* DetectorConstruction::Construct()
0177 {
0178 InitialiseGeometryParameters();
0179
0180 G4GeometryManager::GetInstance()->OpenGeometry();
0181 G4PhysicalVolumeStore::GetInstance()->Clean();
0182 G4LogicalVolumeStore::GetInstance()->Clean();
0183 G4SolidStore::GetInstance()->Clean();
0184
0185
0186
0187
0188 G4Box* solidWorld = new G4Box("World", fWorldXY, fWorldXY, fWorldZ);
0189 G4LogicalVolume* logicWorld = new G4LogicalVolume(solidWorld, fWorldMaterial, "World");
0190 G4VPhysicalVolume* physWorld =
0191 new G4PVPlacement(0, G4ThreeVector(), "World", logicWorld, 0, false, 0);
0192
0193
0194 G4Tubs* solidWin = new G4Tubs("Window", 0., fTargetRadius * 0.25, 0.5 * fWindowZ, 0., twopi);
0195 G4LogicalVolume* logicWin = new G4LogicalVolume(solidWin, fWindowMaterial, "Window");
0196 new G4PVPlacement(0, G4ThreeVector(0., 0., fWindowPosZ), "Window", logicWin, physWorld, false, 0);
0197
0198
0199 G4Tubs* solidTGVolume =
0200 new G4Tubs("TargetVolume", 0., fTargetRadius, 0.5 * fTargetVolumeZ, 0., twopi);
0201 G4LogicalVolume* logicTGVolume =
0202 new G4LogicalVolume(solidTGVolume, fLightMaterial, "TargetVolume");
0203 new G4PVPlacement(0, G4ThreeVector(0., 0., fTargetVolumePosZ), logicTGVolume, "TargetVolume",
0204 logicWorld, false, 0);
0205
0206
0207 G4Tubs* solidTarget1 = new G4Tubs("Target1", 0., fTargetRadius * 0.5, 0.5 * fTarget1Z, 0., twopi);
0208 fLogicTarget1 = new G4LogicalVolume(solidTarget1, fTarget1Material, "Target1");
0209 fTarget1 = new G4PVPlacement(0, G4ThreeVector(0., 0., fTarget1PosZ), fLogicTarget1, "Target1",
0210 logicTGVolume, false, 0);
0211
0212
0213
0214 G4Tubs* solidTarget2 = new G4Tubs("Target2", 0., fTargetRadius * 0.5, 0.5 * fTarget2Z, 0., twopi);
0215 fLogicTarget2 = new G4LogicalVolume(solidTarget2, fTarget2Material, "Target2");
0216 fTarget2 = new G4PVPlacement(0, G4ThreeVector(0., 0., fTarget2PosZ), fLogicTarget2, "Target2",
0217 logicTGVolume, false, 0);
0218
0219
0220
0221
0222 G4Tubs* solidGasVolume =
0223 new G4Tubs("GasVolume", 0., fGasVolumeRadius, 0.5 * fGasVolumeZ, 0., twopi);
0224 G4LogicalVolume* logicGasVolume =
0225 new G4LogicalVolume(solidGasVolume, fLightMaterial, "GasVolume");
0226 fGasVolume = new G4PVPlacement(0, G4ThreeVector(0., 0., fGasVolumePosZ), "GasVolume",
0227 logicGasVolume, physWorld, false, 0);
0228
0229
0230 G4Tubs* sMylarVolume = new G4Tubs("Mylar", 0., fGasVolumeRadius, 0.5 * fMylarVolumeZ, 0., twopi);
0231 G4LogicalVolume* lMylarVolume = new G4LogicalVolume(sMylarVolume, fMylar, "Mylar");
0232 new G4PVPlacement(0, G4ThreeVector(0., 0., fMylarPosZ), "Mylar", lMylarVolume, physWorld, false,
0233 0);
0234
0235
0236 G4Tubs* solidCheckVolume =
0237 new G4Tubs("CheckVolume", 0., fGasVolumeRadius, 0.5 * fCheckVolumeZ, 0., twopi);
0238 fLogicCheckVolume = new G4LogicalVolume(solidCheckVolume, fWorldMaterial, "CheckVolume");
0239 fCheckVolume = new G4PVPlacement(0, G4ThreeVector(0., 0., fCheckVolumePosZ), "CheckVolume",
0240 fLogicCheckVolume, physWorld, false, 0);
0241
0242
0243
0244 G4Box* solidPhantom = new G4Box("Phantom", fPhantomRadius, fPhantomRadius, 0.5 * fPhantomZ);
0245 G4LogicalVolume* logicPhantom = new G4LogicalVolume(solidPhantom, fAbsorberMaterial, "Phantom");
0246 G4VPhysicalVolume* physPhantom = new G4PVPlacement(0, G4ThreeVector(0., 0., fPhantomPosZ),
0247 "Phantom", logicPhantom, physWorld, false, 0);
0248
0249 G4Tubs* solidPh = new G4Tubs("PhantomSD", 0., fAbsorberRadius, 0.5 * fPhantomZ, 0., twopi);
0250 fLogicPh = new G4LogicalVolume(solidPh, fAbsorberMaterial, "PhantomSD");
0251 fPhantom =
0252 new G4PVPlacement(0, G4ThreeVector(0., 0., 0.), "Phantom", fLogicPh, physPhantom, false, 0);
0253 G4cout << "Phantom R= " << fAbsorberRadius << " dz= " << 0.5 * fPhantomZ << G4endl;
0254
0255
0256 G4double absWidth = 0.5 * fAbsorberZ;
0257 G4Tubs* solidAbsorber = new G4Tubs("Absorber", 0., fAbsorberRadius, absWidth, 0., twopi);
0258 fLogicAbsorber = new G4LogicalVolume(solidAbsorber, fAbsorberMaterial, "Absorber");
0259 G4cout << "Absorber R= " << fAbsorberRadius << " dz= " << absWidth << " posZ= " << fAbsorberPosZ
0260 << G4endl;
0261
0262 new G4PVPlacement(0, G4ThreeVector(0., 0., fAbsorberPosZ), "Absorber", fLogicAbsorber, fPhantom,
0263 false, 0);
0264
0265 G4double stepR = fAbsorberRadius / (G4double)fNumR;
0266
0267 G4double r1 = 0.0;
0268 G4double r2 = 0.0;
0269 G4Tubs* solidRing;
0270
0271 G4VisAttributes* VisAtt_ring = new G4VisAttributes(G4VisAttributes::GetInvisible());
0272 for (G4int k = 0; k < fNumR; k++) {
0273 r2 = r1 + stepR;
0274 if (k == fNumR - 1) r2 = fAbsorberRadius;
0275
0276
0277 solidRing = new G4Tubs("Ring", r1, r2, absWidth, 0., twopi);
0278 G4LogicalVolume* logicRing = new G4LogicalVolume(solidRing, fAbsorberMaterial, "Ring");
0279
0280 logicRing->SetVisAttributes(VisAtt_ring);
0281 fLogicRing.push_back(logicRing);
0282 new G4PVPlacement(0, G4ThreeVector(0., 0., 0.), logicRing, "Ring", fLogicAbsorber, false, k);
0283 r1 = r2;
0284 }
0285
0286
0287
0288
0289 G4VisAttributes* VisAtt = 0;
0290 VisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 1.0));
0291 VisAtt->SetVisibility(true);
0292 fLogicAbsorber->SetVisAttributes(VisAtt);
0293
0294 VisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 2.0));
0295 VisAtt->SetVisibility(true);
0296 logicPhantom->SetVisAttributes(VisAtt);
0297
0298 VisAtt = new G4VisAttributes(G4Colour(1.0, 0.0, 2.0));
0299 VisAtt->SetVisibility(true);
0300 fLogicPh->SetVisAttributes(VisAtt);
0301
0302 VisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 0.0));
0303 VisAtt->SetVisibility(true);
0304 fLogicAbsorber->SetVisAttributes(VisAtt);
0305
0306 VisAtt = new G4VisAttributes(G4Colour(0.1, 1.0, 2.0));
0307 VisAtt->SetVisibility(true);
0308 logicWorld->SetVisAttributes(VisAtt);
0309
0310 VisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 0.0));
0311 VisAtt->SetVisibility(true);
0312 logicGasVolume->SetVisAttributes(VisAtt);
0313
0314 VisAtt = new G4VisAttributes(G4Colour(0.0, 0.5, 1.0));
0315 VisAtt->SetVisibility(true);
0316 fLogicTarget1->SetVisAttributes(VisAtt);
0317 fLogicTarget2->SetVisAttributes(VisAtt);
0318 logicTGVolume->SetVisAttributes(VisAtt);
0319
0320 return physWorld;
0321 }
0322
0323 void DetectorConstruction::ConstructSDandField()
0324 {
0325 static G4ThreadLocal G4bool initialized = false;
0326 if (!initialized) {
0327
0328 CheckVolumeSD* fCheckSD = new CheckVolumeSD("checkSD");
0329 (G4SDManager::GetSDMpointer())->AddNewDetector(fCheckSD);
0330 fLogicCheckVolume->SetSensitiveDetector(fCheckSD);
0331
0332 TargetSD* fTargetSD = new TargetSD("targetSD");
0333 (G4SDManager::GetSDMpointer())->AddNewDetector(fTargetSD);
0334 fLogicTarget1->SetSensitiveDetector(fTargetSD);
0335 fLogicTarget2->SetSensitiveDetector(fTargetSD);
0336
0337 PhantomSD* fPhantomSD = new PhantomSD("phantomSD");
0338 (G4SDManager::GetSDMpointer())->AddNewDetector(fPhantomSD);
0339 fPhantomSD->SetShiftZ(fShiftZPh);
0340 for (auto& v : fLogicRing)
0341 v->SetSensitiveDetector(fPhantomSD);
0342 fLogicPh->SetSensitiveDetector(fPhantomSD);
0343 fLogicAbsorber->SetSensitiveDetector(fPhantomSD);
0344 initialized = true;
0345 }
0346 }
0347
0348
0349
0350 void DetectorConstruction::SetTarget1Material(const G4String& mat)
0351 {
0352
0353 G4Material* pttoMaterial = G4NistManager::Instance()->FindOrBuildMaterial(mat);
0354 if (!pttoMaterial) {
0355 G4cout << "Material " << mat << " is not found out!" << G4endl;
0356 }
0357 else if (pttoMaterial != fTarget1Material) {
0358 G4cout << "New target1 material " << mat << G4endl;
0359 if (fLogicTarget1) {
0360 fLogicTarget1->SetMaterial(fTarget1Material);
0361 }
0362 G4RunManager::GetRunManager()->PhysicsHasBeenModified();
0363 }
0364 }
0365
0366
0367
0368 void DetectorConstruction::SetTarget2Material(const G4String& mat)
0369 {
0370
0371 G4Material* pttoMaterial = G4NistManager::Instance()->FindOrBuildMaterial(mat);
0372
0373 if (!pttoMaterial) {
0374 G4cout << "Material " << mat << " is not found out!" << G4endl;
0375 }
0376 else if (pttoMaterial != fTarget2Material) {
0377 fTarget2Material = pttoMaterial;
0378 G4cout << "New target2 material " << mat << G4endl;
0379 if (fLogicTarget2) {
0380 fLogicTarget2->SetMaterial(fTarget2Material);
0381 }
0382 G4RunManager::GetRunManager()->PhysicsHasBeenModified();
0383 }
0384 }
0385
0386
0387
0388 void DetectorConstruction::DumpGeometryParameters()
0389 {
0390 G4cout << "===================================================" << G4endl;
0391 G4cout << "# GammaTherapy Geometry #" << G4endl;
0392 G4cout << "===================================================" << G4endl;
0393 G4cout << " World width= " << fWorldZ / mm << " mm " << G4endl;
0394 G4cout << " Window width= " << fWindowZ / mm << " mm position = " << fWindowPosZ / mm
0395 << " mm:" << G4endl;
0396 G4cout << " TargetV width= " << fTargetVolumeZ / mm
0397 << " mm position = " << fTargetVolumePosZ / mm << " mm:" << G4endl;
0398 G4cout << " Target1 width= " << fTarget1Z / mm << " mm position = " << fTarget1PosZ / mm
0399 << " mm:" << G4endl;
0400 G4cout << " Target2 width= " << fTarget2Z / mm << " mm position = " << fTarget2PosZ / mm
0401 << " mm:" << G4endl;
0402 G4cout << " Gas width= " << fGasVolumeZ / mm << " mm position = " << fGasVolumePosZ / mm
0403 << " mm:" << G4endl;
0404 G4cout << " Mylar width= " << fMylarVolumeZ / mm << " mm position = " << fMylarPosZ / mm
0405 << " mm:" << G4endl;
0406 G4cout << " Check width= " << fCheckVolumeZ / mm
0407 << " mm position = " << fCheckVolumePosZ / mm << " mm:" << G4endl;
0408 G4cout << " Air width= " << fAirZ / mm << " mm " << G4endl;
0409 G4cout << " Phantom width= " << fPhantomZ / mm << " mm position = " << fPhantomPosZ / mm
0410 << " mm:" << G4endl;
0411 G4cout << " Absorb width= " << fAbsorberZ / mm << " mm position = " << fAbsorberPosZ / mm
0412 << " mm:" << G4endl;
0413 G4cout << " Absorb shift= " << fShiftZPh / mm << " mm " << G4endl;
0414 G4cout << " Target1 " << fTarget1Material->GetName() << G4endl;
0415 G4cout << " Target2 " << fTarget2Material->GetName() << G4endl;
0416 G4cout << " Phantom " << fAbsorberMaterial->GetName() << G4endl;
0417 G4cout << "===================================================" << G4endl;
0418 }