Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 /// \file RE06/src/RE06DetectorConstruction.cc 27 /// \brief Implementation of the RE06DetectorConstruction class 28 // 29 // 30 31 #include "RE06DetectorConstruction.hh" 32 33 #include "RE06DetectorMessenger.hh" 34 #include "RE06ParallelWorld.hh" 35 #include "RE06PrimaryGeneratorAction.hh" 36 37 #include "G4Box.hh" 38 #include "G4Colour.hh" 39 #include "G4LogicalVolume.hh" 40 #include "G4Material.hh" 41 #include "G4MultiFunctionalDetector.hh" 42 #include "G4PSEnergyDeposit.hh" 43 #include "G4PSMinKinEAtGeneration.hh" 44 #include "G4PSNofSecondary.hh" 45 #include "G4PSNofStep.hh" 46 #include "G4PSTrackLength.hh" 47 #include "G4PVPlacement.hh" 48 #include "G4PVReplica.hh" 49 #include "G4PhysicalConstants.hh" 50 #include "G4RunManager.hh" 51 #include "G4SDManager.hh" 52 #include "G4SDParticleFilter.hh" 53 #include "G4SystemOfUnits.hh" 54 #include "G4VPrimitiveScorer.hh" 55 #include "G4VSDFilter.hh" 56 #include "G4VisAttributes.hh" 57 #include "G4ios.hh" 58 59 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 60 61 G4ThreadLocal G4bool RE06DetectorConstruction::fConstructedSDandField = false; 62 63 RE06DetectorConstruction::RE06DetectorConstruction() 64 : G4VUserDetectorConstruction(), 65 fNumberOfLayers(40), 66 fTotalThickness(2.0 * m), 67 fLayerThickness(0.), 68 fConstructed(false), 69 fWorldMaterial(0), 70 fAbsorberMaterial(0), 71 fGapMaterial(0), 72 fLayerSolid(0), 73 fGapSolid(0), 74 fWorldLogical(0), 75 fWorldPhysical(0), 76 fSerial(false), 77 fDetectorMessenger(0), 78 fVerboseLevel(1) 79 { 80 fLayerThickness = fTotalThickness / fNumberOfLayers; 81 82 for (size_t i = 0; i < 3; i++) { 83 fCalorLogical[i] = 0; 84 fLayerLogical[i] = 0; 85 fGapLogical[i] = 0; 86 fCalorPhysical[i] = 0; 87 fLayerPhysical[i] = 0; 88 fGapPhysical[i] = 0; 89 } 90 91 fCalName[0] = "Calor-A"; 92 fCalName[1] = "Calor-B"; 93 fCalName[2] = "Calor-C"; 94 95 fDetectorMessenger = new RE06DetectorMessenger(this); 96 } 97 98 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 99 100 RE06DetectorConstruction::~RE06DetectorConstruction() 101 { 102 delete fDetectorMessenger; 103 } 104 105 G4VPhysicalVolume* RE06DetectorConstruction::Construct() 106 { 107 if (!fConstructed) { 108 fConstructed = true; 109 DefineMaterials(); 110 SetupGeometry(); 111 } 112 if (GetVerboseLevel() > 0) { 113 PrintCalorParameters(); 114 } 115 return fWorldPhysical; 116 } 117 118 void RE06DetectorConstruction::ConstructSDandField() 119 { 120 if (!fConstructedSDandField) { 121 fConstructedSDandField = true; 122 SetupDetectors(); 123 } 124 } 125 126 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 127 128 void RE06DetectorConstruction::DefineMaterials() 129 { 130 G4String name, symbol; // a=mass of a mole; 131 G4double a, z, density; // z=mean number of protons; 132 G4int iz; // iz=number of protons in an isotope; 133 G4int n; // n=number of nucleons in an isotope; 134 135 G4int ncomponents, natoms; 136 G4double abundance, fractionmass; 137 G4double temperature, pressure; 138 139 // 140 // define Elements 141 // 142 143 a = 1.01 * g / mole; 144 G4Element* H = new G4Element(name = "Hydrogen", symbol = "H", z = 1., a); 145 146 a = 12.01 * g / mole; 147 G4Element* C = new G4Element(name = "Carbon", symbol = "C", z = 6., a); 148 149 a = 14.01 * g / mole; 150 G4Element* N = new G4Element(name = "Nitrogen", symbol = "N", z = 7., a); 151 152 a = 16.00 * g / mole; 153 G4Element* O = new G4Element(name = "Oxygen", symbol = "O", z = 8., a); 154 155 // 156 // define an Element from isotopes, by relative abundance 157 // 158 159 G4Isotope* U5 = new G4Isotope(name = "U235", iz = 92, n = 235, a = 235.01 * g / mole); 160 G4Isotope* U8 = new G4Isotope(name = "U238", iz = 92, n = 238, a = 238.03 * g / mole); 161 162 G4Element* U = new G4Element(name = "enriched Uranium", symbol = "U", ncomponents = 2); 163 U->AddIsotope(U5, abundance = 90. * perCent); 164 U->AddIsotope(U8, abundance = 10. * perCent); 165 166 // 167 // define simple materials 168 // 169 170 new G4Material(name = "Aluminium", z = 13., a = 26.98 * g / mole, density = 2.700 * g / cm3); 171 new G4Material(name = "Silicon", z = 14., a = 28.09 * g / mole, density = 2.33 * g / cm3); 172 new G4Material(name = "Iron", z = 26., a = 55.85 * g / mole, density = 7.87 * g / cm3); 173 new G4Material(name = "ArgonGas", z = 18., a = 39.95 * g / mole, density = 1.782 * mg / cm3); 174 new G4Material(name = "He", z = 2., a = 4.0 * g / mole, density = 0.1786e-03 * g / cm3); 175 176 density = 1.390 * g / cm3; 177 a = 39.95 * g / mole; 178 G4Material* lAr = new G4Material(name = "liquidArgon", z = 18., a, density); 179 180 density = 11.35 * g / cm3; 181 a = 207.19 * g / mole; 182 G4Material* Pb = new G4Material(name = "Lead", z = 82., a, density); 183 184 // 185 // define a material from elements. case 1: chemical molecule 186 // 187 188 density = 1.000 * g / cm3; 189 G4Material* H2O = new G4Material(name = "Water", density, ncomponents = 2); 190 H2O->AddElement(H, natoms = 2); 191 H2O->AddElement(O, natoms = 1); 192 193 density = 1.032 * g / cm3; 194 G4Material* Sci = new G4Material(name = "Scintillator", density, ncomponents = 2); 195 Sci->AddElement(C, natoms = 9); 196 Sci->AddElement(H, natoms = 10); 197 198 // 199 // define a material from elements. case 2: mixture by fractional mass 200 // 201 202 density = 1.290 * mg / cm3; 203 G4Material* Air = new G4Material(name = "Air", density, ncomponents = 2); 204 Air->AddElement(N, fractionmass = 0.7); 205 Air->AddElement(O, fractionmass = 0.3); 206 207 // 208 // examples of vacuum 209 // 210 211 density = universe_mean_density; 212 pressure = 3.e-18 * pascal; 213 temperature = 2.73 * kelvin; 214 G4Material* Vacuum = new G4Material(name = "Galactic", z = 1., a = 1.01 * g / mole, density, 215 kStateGas, temperature, pressure); 216 217 if (GetVerboseLevel() > 1) { 218 G4cout << *(G4Material::GetMaterialTable()) << G4endl; 219 } 220 221 // default materials of the calorimeter 222 fWorldMaterial = Vacuum; 223 fAbsorberMaterial = Pb; 224 fGapMaterial = lAr; 225 } 226 227 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 228 229 void RE06DetectorConstruction::SetupGeometry() 230 { 231 // 232 // World 233 // 234 G4VSolid* worldSolid = new G4Box("World", 2. * m, 2. * m, fTotalThickness * 2.); 235 fWorldLogical = new G4LogicalVolume(worldSolid, fWorldMaterial, "World"); 236 fWorldPhysical = new G4PVPlacement(0, G4ThreeVector(), fWorldLogical, "World", 0, false, 0); 237 238 // 239 // Calorimeter 240 // 241 G4VSolid* calorSolid = new G4Box("Calor", 0.5 * m, 0.5 * m, fTotalThickness / 2.); 242 G4int i; 243 for (i = 0; i < 3; i++) { 244 fCalorLogical[i] = new G4LogicalVolume(calorSolid, fAbsorberMaterial, fCalName[i]); 245 if (fSerial) { 246 fCalorPhysical[i] = 247 new G4PVPlacement(0, G4ThreeVector(0., 0., G4double(i - 1) * fTotalThickness), 248 fCalorLogical[i], fCalName[i], fWorldLogical, false, i); 249 } 250 else { 251 fCalorPhysical[i] = new G4PVPlacement(0, G4ThreeVector(0., G4double(i - 1) * m, 0.), 252 fCalorLogical[i], fCalName[i], fWorldLogical, false, i); 253 } 254 } 255 256 // 257 // Layers --- as absorbers 258 // 259 fLayerSolid = new G4Box("Layer", 0.5 * m, 0.5 * m, fLayerThickness / 2.); 260 for (i = 0; i < 3; i++) { 261 fLayerLogical[i] = 262 new G4LogicalVolume(fLayerSolid, fAbsorberMaterial, fCalName[i] + "_LayerLog"); 263 fLayerPhysical[i] = new G4PVReplica(fCalName[i] + "_Layer", fLayerLogical[i], fCalorLogical[i], 264 kZAxis, fNumberOfLayers, fLayerThickness); 265 } 266 267 // 268 // Gap 269 // 270 fGapSolid = new G4Box("Gap", 0.5 * m, 0.5 * m, fLayerThickness / 4.); 271 for (i = 0; i < 3; i++) { 272 fGapLogical[i] = new G4LogicalVolume(fGapSolid, fGapMaterial, fCalName[i] + "_Gap"); 273 fGapPhysical[i] = 274 new G4PVPlacement(0, G4ThreeVector(0., 0., fLayerThickness / 4.), fGapLogical[i], 275 fCalName[i] + "_gap", fLayerLogical[i], false, 0); 276 } 277 278 // 279 // Regions 280 // 281 for (i = 0; i < 3; i++) { 282 G4Region* aRegion = new G4Region(fCalName[i]); 283 fCalorLogical[i]->SetRegion(aRegion); 284 aRegion->AddRootLogicalVolume(fCalorLogical[i]); 285 } 286 287 // 288 // Visualization attributes 289 // 290 fWorldLogical->SetVisAttributes(G4VisAttributes::GetInvisible()); 291 G4VisAttributes* simpleBoxVisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 1.0)); 292 simpleBoxVisAtt->SetVisibility(true); 293 for (i = 0; i < 3; i++) { 294 fCalorLogical[i]->SetVisAttributes(simpleBoxVisAtt); 295 fLayerLogical[i]->SetVisAttributes(simpleBoxVisAtt); 296 fGapLogical[i]->SetVisAttributes(simpleBoxVisAtt); 297 } 298 } 299 300 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 301 302 void RE06DetectorConstruction::SetupDetectors() 303 { 304 G4SDManager::GetSDMpointer()->SetVerboseLevel(1); 305 G4String filterName, particleName; 306 307 G4SDParticleFilter* gammaFilter = 308 new G4SDParticleFilter(filterName = "gammaFilter", particleName = "gamma"); 309 G4SDParticleFilter* electronFilter = 310 new G4SDParticleFilter(filterName = "electronFilter", particleName = "e-"); 311 G4SDParticleFilter* positronFilter = 312 new G4SDParticleFilter(filterName = "positronFilter", particleName = "e+"); 313 G4SDParticleFilter* epFilter = new G4SDParticleFilter(filterName = "epFilter"); 314 epFilter->add(particleName = "e-"); 315 epFilter->add(particleName = "e+"); 316 317 for (G4int i = 0; i < 3; i++) { 318 for (G4int j = 0; j < 2; j++) { 319 // Loop counter j = 0 : absorber 320 // = 1 : gap 321 G4String detName = fCalName[i]; 322 if (j == 0) { 323 detName += "_abs"; 324 } 325 else { 326 detName += "_gap"; 327 } 328 G4MultiFunctionalDetector* det = new G4MultiFunctionalDetector(detName); 329 G4SDManager::GetSDMpointer()->AddNewDetector(det); 330 331 // The second argument in each primitive means the "level" of geometrical 332 // hierarchy, the copy number of that level is used as the key of the 333 // G4THitsMap. 334 // For absorber (j = 0), the copy number of its own physical volume is used. 335 // For gap (j = 1), the copy number of its mother physical volume is used, 336 // since there is only one physical volume of gap is placed with respect 337 // to its mother. 338 G4VPrimitiveScorer* primitive; 339 primitive = new G4PSEnergyDeposit("eDep", j); 340 det->RegisterPrimitive(primitive); 341 primitive = new G4PSNofSecondary("nGamma", j); 342 primitive->SetFilter(gammaFilter); 343 det->RegisterPrimitive(primitive); 344 primitive = new G4PSNofSecondary("nElectron", j); 345 primitive->SetFilter(electronFilter); 346 det->RegisterPrimitive(primitive); 347 primitive = new G4PSNofSecondary("nPositron", j); 348 primitive->SetFilter(positronFilter); 349 det->RegisterPrimitive(primitive); 350 primitive = new G4PSMinKinEAtGeneration("minEkinGamma", j); 351 primitive->SetFilter(gammaFilter); 352 det->RegisterPrimitive(primitive); 353 primitive = new G4PSMinKinEAtGeneration("minEkinElectron", j); 354 primitive->SetFilter(electronFilter); 355 det->RegisterPrimitive(primitive); 356 primitive = new G4PSMinKinEAtGeneration("minEkinPositron", j); 357 primitive->SetFilter(positronFilter); 358 det->RegisterPrimitive(primitive); 359 primitive = new G4PSTrackLength("trackLength", j); 360 primitive->SetFilter(epFilter); 361 det->RegisterPrimitive(primitive); 362 primitive = new G4PSNofStep("nStep", j); 363 primitive->SetFilter(epFilter); 364 det->RegisterPrimitive(primitive); 365 366 if (j == 0) { 367 SetSensitiveDetector(fLayerLogical[i], det); 368 } 369 else { 370 SetSensitiveDetector(fGapLogical[i], det); 371 } 372 } 373 } 374 G4SDManager::GetSDMpointer()->SetVerboseLevel(0); 375 } 376 377 void RE06DetectorConstruction::PrintCalorParameters() const 378 { 379 G4cout << "--------------------------------------------------------" << G4endl; 380 if (fSerial) { 381 G4cout << " Calorimeters are placed in serial." << G4endl; 382 } 383 else { 384 G4cout << " Calorimeters are placed in parallel." << G4endl; 385 } 386 G4cout << " Absorber is made of " << fAbsorberMaterial->GetName() << G4endl << " Gap is made of " 387 << fGapMaterial->GetName() << G4endl 388 << "--------------------------------------------------------" << G4endl; 389 } 390 391 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 392 393 void RE06DetectorConstruction::SetAbsorberMaterial(G4String materialChoice) 394 { 395 // search the material by its name 396 G4Material* pttoMaterial = G4Material::GetMaterial(materialChoice); 397 if (pttoMaterial) { 398 fAbsorberMaterial = pttoMaterial; 399 if (fConstructed) 400 for (size_t i = 0; i < 3; i++) { 401 fCalorLogical[i]->SetMaterial(fAbsorberMaterial); 402 fLayerLogical[i]->SetMaterial(fAbsorberMaterial); 403 } 404 G4RunManager::GetRunManager()->GeometryHasBeenModified(); 405 if (GetVerboseLevel() > 1) { 406 PrintCalorParameters(); 407 } 408 } 409 else { 410 G4cerr << materialChoice << " is not defined. - Command is ignored." << G4endl; 411 } 412 } 413 414 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 415 416 G4String RE06DetectorConstruction::GetAbsorberMaterial() const 417 { 418 return fAbsorberMaterial->GetName(); 419 } 420 421 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 422 423 void RE06DetectorConstruction::SetGapMaterial(G4String materialChoice) 424 { 425 // search the material by its name 426 G4Material* pttoMaterial = G4Material::GetMaterial(materialChoice); 427 if (pttoMaterial) { 428 fGapMaterial = pttoMaterial; 429 if (fConstructed) 430 for (size_t i = 0; i < 3; i++) { 431 fGapLogical[i]->SetMaterial(fGapMaterial); 432 } 433 G4RunManager::GetRunManager()->GeometryHasBeenModified(); 434 if (GetVerboseLevel() > 1) { 435 PrintCalorParameters(); 436 } 437 } 438 else { 439 G4cerr << materialChoice << " is not defined. - Command is ignored." << G4endl; 440 } 441 } 442 443 G4String RE06DetectorConstruction::GetGapMaterial() const 444 { 445 return fGapMaterial->GetName(); 446 } 447 448 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 449 450 void RE06DetectorConstruction::SetSerialGeometry(G4bool serial) 451 { 452 if (fSerial == serial) return; 453 fSerial = serial; 454 RE06PrimaryGeneratorAction* gen = 455 (RE06PrimaryGeneratorAction*)(G4RunManager::GetRunManager()->GetUserPrimaryGeneratorAction()); 456 if (gen) gen->SetSerial(fSerial); 457 if (!fConstructed) return; 458 for (G4int i = 0; i < 3; i++) { 459 if (fSerial) { 460 fCalorPhysical[i]->SetTranslation(G4ThreeVector(0., 0., G4double(i - 1) * 2. * m)); 461 } 462 else { 463 fCalorPhysical[i]->SetTranslation(G4ThreeVector(0., G4double(i - 1) * m, 0.)); 464 } 465 } 466 ((RE06ParallelWorld*)GetParallelWorld(0))->SetSerialGeometry(serial); 467 G4RunManager::GetRunManager()->GeometryHasBeenModified(); 468 } 469 470 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 471 472 void RE06DetectorConstruction::SetNumberOfLayers(G4int nl) 473 { 474 fNumberOfLayers = nl; 475 fLayerThickness = fTotalThickness / fNumberOfLayers; 476 if (!fConstructed) return; 477 478 fLayerSolid->SetZHalfLength(fLayerThickness / 2.); 479 fGapSolid->SetZHalfLength(fLayerThickness / 4.); 480 for (size_t i = 0; i < 3; i++) { 481 fCalorLogical[i]->RemoveDaughter(fLayerPhysical[i]); 482 delete fLayerPhysical[i]; 483 fLayerPhysical[i] = new G4PVReplica(fCalName[i] + "_Layer", fLayerLogical[i], fCalorLogical[i], 484 kZAxis, fNumberOfLayers, fLayerThickness); 485 fGapPhysical[i]->SetTranslation(G4ThreeVector(0., 0., fLayerThickness / 4.)); 486 } 487 G4RunManager::GetRunManager()->GeometryHasBeenModified(); 488 } 489 490 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 491 492 void RE06DetectorConstruction::AddMaterial() 493 { 494 static G4bool isAdded = false; 495 496 if (isAdded) return; 497 498 G4String name, symbol; // a=mass of a mole; 499 G4double a, z, density; // z=mean number of protons; 500 501 G4int ncomponents, natoms; 502 503 // 504 // define simple materials 505 // 506 507 new G4Material(name = "Copper", z = 29., a = 63.546 * g / mole, density = 8.96 * g / cm3); 508 new G4Material(name = "Tungsten", z = 74., a = 183.84 * g / mole, density = 19.3 * g / cm3); 509 510 G4Element* C = G4Element::GetElement("Carbon"); 511 G4Element* O = G4Element::GetElement("Oxygen"); 512 513 G4Material* CO2 = new G4Material("CarbonicGas", density = 27. * mg / cm3, ncomponents = 2, 514 kStateGas, 325. * kelvin, 50. * atmosphere); 515 CO2->AddElement(C, natoms = 1); 516 CO2->AddElement(O, natoms = 2); 517 518 isAdded = true; 519 } 520 521 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 522