522 lines
17 KiB
C++
522 lines
17 KiB
C++
//
|
|
// ********************************************************************
|
|
// * License and Disclaimer *
|
|
// * *
|
|
// * The Geant4 software is copyright of the Copyright Holders of *
|
|
// * the Geant4 Collaboration. It is provided under the terms and *
|
|
// * conditions of the Geant4 Software License, included in the file *
|
|
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
|
// * include a list of copyright holders. *
|
|
// * *
|
|
// * Neither the authors of this software system, nor their employing *
|
|
// * institutes,nor the agencies providing financial support for this *
|
|
// * work make any representation or warranty, express or implied, *
|
|
// * regarding this software system or assume any liability for its *
|
|
// * use. Please see the license in the file LICENSE and URL above *
|
|
// * for the full disclaimer and the limitation of liability. *
|
|
// * *
|
|
// * This code implementation is the result of the scientific and *
|
|
// * technical work of the GEANT4 collaboration. *
|
|
// * By using, copying, modifying or distributing the software (or *
|
|
// * any work based on the software) you agree to acknowledge its *
|
|
// * use in resulting scientific publications, and indicate your *
|
|
// * acceptance of all terms of the Geant4 Software license. *
|
|
// ********************************************************************
|
|
//
|
|
/// \file RE06/src/RE06DetectorConstruction.cc
|
|
/// \brief Implementation of the RE06DetectorConstruction class
|
|
//
|
|
//
|
|
|
|
#include "RE06DetectorConstruction.hh"
|
|
|
|
#include "RE06DetectorMessenger.hh"
|
|
#include "RE06ParallelWorld.hh"
|
|
#include "RE06PrimaryGeneratorAction.hh"
|
|
|
|
#include "G4Box.hh"
|
|
#include "G4Colour.hh"
|
|
#include "G4LogicalVolume.hh"
|
|
#include "G4Material.hh"
|
|
#include "G4MultiFunctionalDetector.hh"
|
|
#include "G4PSEnergyDeposit.hh"
|
|
#include "G4PSMinKinEAtGeneration.hh"
|
|
#include "G4PSNofSecondary.hh"
|
|
#include "G4PSNofStep.hh"
|
|
#include "G4PSTrackLength.hh"
|
|
#include "G4PVPlacement.hh"
|
|
#include "G4PVReplica.hh"
|
|
#include "G4PhysicalConstants.hh"
|
|
#include "G4RunManager.hh"
|
|
#include "G4SDManager.hh"
|
|
#include "G4SDParticleFilter.hh"
|
|
#include "G4SystemOfUnits.hh"
|
|
#include "G4VPrimitiveScorer.hh"
|
|
#include "G4VSDFilter.hh"
|
|
#include "G4VisAttributes.hh"
|
|
#include "G4ios.hh"
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4ThreadLocal G4bool RE06DetectorConstruction::fConstructedSDandField = false;
|
|
|
|
RE06DetectorConstruction::RE06DetectorConstruction()
|
|
: G4VUserDetectorConstruction(),
|
|
fNumberOfLayers(40),
|
|
fTotalThickness(2.0 * m),
|
|
fLayerThickness(0.),
|
|
fConstructed(false),
|
|
fWorldMaterial(0),
|
|
fAbsorberMaterial(0),
|
|
fGapMaterial(0),
|
|
fLayerSolid(0),
|
|
fGapSolid(0),
|
|
fWorldLogical(0),
|
|
fWorldPhysical(0),
|
|
fSerial(false),
|
|
fDetectorMessenger(0),
|
|
fVerboseLevel(1)
|
|
{
|
|
fLayerThickness = fTotalThickness / fNumberOfLayers;
|
|
|
|
for (size_t i = 0; i < 3; i++) {
|
|
fCalorLogical[i] = 0;
|
|
fLayerLogical[i] = 0;
|
|
fGapLogical[i] = 0;
|
|
fCalorPhysical[i] = 0;
|
|
fLayerPhysical[i] = 0;
|
|
fGapPhysical[i] = 0;
|
|
}
|
|
|
|
fCalName[0] = "Calor-A";
|
|
fCalName[1] = "Calor-B";
|
|
fCalName[2] = "Calor-C";
|
|
|
|
fDetectorMessenger = new RE06DetectorMessenger(this);
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
RE06DetectorConstruction::~RE06DetectorConstruction()
|
|
{
|
|
delete fDetectorMessenger;
|
|
}
|
|
|
|
G4VPhysicalVolume* RE06DetectorConstruction::Construct()
|
|
{
|
|
if (!fConstructed) {
|
|
fConstructed = true;
|
|
DefineMaterials();
|
|
SetupGeometry();
|
|
}
|
|
if (GetVerboseLevel() > 0) {
|
|
PrintCalorParameters();
|
|
}
|
|
return fWorldPhysical;
|
|
}
|
|
|
|
void RE06DetectorConstruction::ConstructSDandField()
|
|
{
|
|
if (!fConstructedSDandField) {
|
|
fConstructedSDandField = true;
|
|
SetupDetectors();
|
|
}
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::DefineMaterials()
|
|
{
|
|
G4String name, symbol; // a=mass of a mole;
|
|
G4double a, z, density; // z=mean number of protons;
|
|
G4int iz; // iz=number of protons in an isotope;
|
|
G4int n; // n=number of nucleons in an isotope;
|
|
|
|
G4int ncomponents, natoms;
|
|
G4double abundance, fractionmass;
|
|
G4double temperature, pressure;
|
|
|
|
//
|
|
// define Elements
|
|
//
|
|
|
|
a = 1.01 * g / mole;
|
|
G4Element* H = new G4Element(name = "Hydrogen", symbol = "H", z = 1., a);
|
|
|
|
a = 12.01 * g / mole;
|
|
G4Element* C = new G4Element(name = "Carbon", symbol = "C", z = 6., a);
|
|
|
|
a = 14.01 * g / mole;
|
|
G4Element* N = new G4Element(name = "Nitrogen", symbol = "N", z = 7., a);
|
|
|
|
a = 16.00 * g / mole;
|
|
G4Element* O = new G4Element(name = "Oxygen", symbol = "O", z = 8., a);
|
|
|
|
//
|
|
// define an Element from isotopes, by relative abundance
|
|
//
|
|
|
|
G4Isotope* U5 = new G4Isotope(name = "U235", iz = 92, n = 235, a = 235.01 * g / mole);
|
|
G4Isotope* U8 = new G4Isotope(name = "U238", iz = 92, n = 238, a = 238.03 * g / mole);
|
|
|
|
G4Element* U = new G4Element(name = "enriched Uranium", symbol = "U", ncomponents = 2);
|
|
U->AddIsotope(U5, abundance = 90. * perCent);
|
|
U->AddIsotope(U8, abundance = 10. * perCent);
|
|
|
|
//
|
|
// define simple materials
|
|
//
|
|
|
|
new G4Material(name = "Aluminium", z = 13., a = 26.98 * g / mole, density = 2.700 * g / cm3);
|
|
new G4Material(name = "Silicon", z = 14., a = 28.09 * g / mole, density = 2.33 * g / cm3);
|
|
new G4Material(name = "Iron", z = 26., a = 55.85 * g / mole, density = 7.87 * g / cm3);
|
|
new G4Material(name = "ArgonGas", z = 18., a = 39.95 * g / mole, density = 1.782 * mg / cm3);
|
|
new G4Material(name = "He", z = 2., a = 4.0 * g / mole, density = 0.1786e-03 * g / cm3);
|
|
|
|
density = 1.390 * g / cm3;
|
|
a = 39.95 * g / mole;
|
|
G4Material* lAr = new G4Material(name = "liquidArgon", z = 18., a, density);
|
|
|
|
density = 11.35 * g / cm3;
|
|
a = 207.19 * g / mole;
|
|
G4Material* Pb = new G4Material(name = "Lead", z = 82., a, density);
|
|
|
|
//
|
|
// define a material from elements. case 1: chemical molecule
|
|
//
|
|
|
|
density = 1.000 * g / cm3;
|
|
G4Material* H2O = new G4Material(name = "Water", density, ncomponents = 2);
|
|
H2O->AddElement(H, natoms = 2);
|
|
H2O->AddElement(O, natoms = 1);
|
|
|
|
density = 1.032 * g / cm3;
|
|
G4Material* Sci = new G4Material(name = "Scintillator", density, ncomponents = 2);
|
|
Sci->AddElement(C, natoms = 9);
|
|
Sci->AddElement(H, natoms = 10);
|
|
|
|
//
|
|
// define a material from elements. case 2: mixture by fractional mass
|
|
//
|
|
|
|
density = 1.290 * mg / cm3;
|
|
G4Material* Air = new G4Material(name = "Air", density, ncomponents = 2);
|
|
Air->AddElement(N, fractionmass = 0.7);
|
|
Air->AddElement(O, fractionmass = 0.3);
|
|
|
|
//
|
|
// examples of vacuum
|
|
//
|
|
|
|
density = universe_mean_density;
|
|
pressure = 3.e-18 * pascal;
|
|
temperature = 2.73 * kelvin;
|
|
G4Material* Vacuum = new G4Material(name = "Galactic", z = 1., a = 1.01 * g / mole, density,
|
|
kStateGas, temperature, pressure);
|
|
|
|
if (GetVerboseLevel() > 1) {
|
|
G4cout << *(G4Material::GetMaterialTable()) << G4endl;
|
|
}
|
|
|
|
// default materials of the calorimeter
|
|
fWorldMaterial = Vacuum;
|
|
fAbsorberMaterial = Pb;
|
|
fGapMaterial = lAr;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::SetupGeometry()
|
|
{
|
|
//
|
|
// World
|
|
//
|
|
G4VSolid* worldSolid = new G4Box("World", 2. * m, 2. * m, fTotalThickness * 2.);
|
|
fWorldLogical = new G4LogicalVolume(worldSolid, fWorldMaterial, "World");
|
|
fWorldPhysical = new G4PVPlacement(0, G4ThreeVector(), fWorldLogical, "World", 0, false, 0);
|
|
|
|
//
|
|
// Calorimeter
|
|
//
|
|
G4VSolid* calorSolid = new G4Box("Calor", 0.5 * m, 0.5 * m, fTotalThickness / 2.);
|
|
G4int i;
|
|
for (i = 0; i < 3; i++) {
|
|
fCalorLogical[i] = new G4LogicalVolume(calorSolid, fAbsorberMaterial, fCalName[i]);
|
|
if (fSerial) {
|
|
fCalorPhysical[i] =
|
|
new G4PVPlacement(0, G4ThreeVector(0., 0., G4double(i - 1) * fTotalThickness),
|
|
fCalorLogical[i], fCalName[i], fWorldLogical, false, i);
|
|
}
|
|
else {
|
|
fCalorPhysical[i] = new G4PVPlacement(0, G4ThreeVector(0., G4double(i - 1) * m, 0.),
|
|
fCalorLogical[i], fCalName[i], fWorldLogical, false, i);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Layers --- as absorbers
|
|
//
|
|
fLayerSolid = new G4Box("Layer", 0.5 * m, 0.5 * m, fLayerThickness / 2.);
|
|
for (i = 0; i < 3; i++) {
|
|
fLayerLogical[i] =
|
|
new G4LogicalVolume(fLayerSolid, fAbsorberMaterial, fCalName[i] + "_LayerLog");
|
|
fLayerPhysical[i] = new G4PVReplica(fCalName[i] + "_Layer", fLayerLogical[i], fCalorLogical[i],
|
|
kZAxis, fNumberOfLayers, fLayerThickness);
|
|
}
|
|
|
|
//
|
|
// Gap
|
|
//
|
|
fGapSolid = new G4Box("Gap", 0.5 * m, 0.5 * m, fLayerThickness / 4.);
|
|
for (i = 0; i < 3; i++) {
|
|
fGapLogical[i] = new G4LogicalVolume(fGapSolid, fGapMaterial, fCalName[i] + "_Gap");
|
|
fGapPhysical[i] =
|
|
new G4PVPlacement(0, G4ThreeVector(0., 0., fLayerThickness / 4.), fGapLogical[i],
|
|
fCalName[i] + "_gap", fLayerLogical[i], false, 0);
|
|
}
|
|
|
|
//
|
|
// Regions
|
|
//
|
|
for (i = 0; i < 3; i++) {
|
|
G4Region* aRegion = new G4Region(fCalName[i]);
|
|
fCalorLogical[i]->SetRegion(aRegion);
|
|
aRegion->AddRootLogicalVolume(fCalorLogical[i]);
|
|
}
|
|
|
|
//
|
|
// Visualization attributes
|
|
//
|
|
fWorldLogical->SetVisAttributes(G4VisAttributes::GetInvisible());
|
|
G4VisAttributes* simpleBoxVisAtt = new G4VisAttributes(G4Colour(1.0, 1.0, 1.0));
|
|
simpleBoxVisAtt->SetVisibility(true);
|
|
for (i = 0; i < 3; i++) {
|
|
fCalorLogical[i]->SetVisAttributes(simpleBoxVisAtt);
|
|
fLayerLogical[i]->SetVisAttributes(simpleBoxVisAtt);
|
|
fGapLogical[i]->SetVisAttributes(simpleBoxVisAtt);
|
|
}
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::SetupDetectors()
|
|
{
|
|
G4SDManager::GetSDMpointer()->SetVerboseLevel(1);
|
|
G4String filterName, particleName;
|
|
|
|
G4SDParticleFilter* gammaFilter =
|
|
new G4SDParticleFilter(filterName = "gammaFilter", particleName = "gamma");
|
|
G4SDParticleFilter* electronFilter =
|
|
new G4SDParticleFilter(filterName = "electronFilter", particleName = "e-");
|
|
G4SDParticleFilter* positronFilter =
|
|
new G4SDParticleFilter(filterName = "positronFilter", particleName = "e+");
|
|
G4SDParticleFilter* epFilter = new G4SDParticleFilter(filterName = "epFilter");
|
|
epFilter->add(particleName = "e-");
|
|
epFilter->add(particleName = "e+");
|
|
|
|
for (G4int i = 0; i < 3; i++) {
|
|
for (G4int j = 0; j < 2; j++) {
|
|
// Loop counter j = 0 : absorber
|
|
// = 1 : gap
|
|
G4String detName = fCalName[i];
|
|
if (j == 0) {
|
|
detName += "_abs";
|
|
}
|
|
else {
|
|
detName += "_gap";
|
|
}
|
|
G4MultiFunctionalDetector* det = new G4MultiFunctionalDetector(detName);
|
|
G4SDManager::GetSDMpointer()->AddNewDetector(det);
|
|
|
|
// The second argument in each primitive means the "level" of geometrical
|
|
// hierarchy, the copy number of that level is used as the key of the
|
|
// G4THitsMap.
|
|
// For absorber (j = 0), the copy number of its own physical volume is used.
|
|
// For gap (j = 1), the copy number of its mother physical volume is used,
|
|
// since there is only one physical volume of gap is placed with respect
|
|
// to its mother.
|
|
G4VPrimitiveScorer* primitive;
|
|
primitive = new G4PSEnergyDeposit("eDep", j);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSNofSecondary("nGamma", j);
|
|
primitive->SetFilter(gammaFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSNofSecondary("nElectron", j);
|
|
primitive->SetFilter(electronFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSNofSecondary("nPositron", j);
|
|
primitive->SetFilter(positronFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSMinKinEAtGeneration("minEkinGamma", j);
|
|
primitive->SetFilter(gammaFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSMinKinEAtGeneration("minEkinElectron", j);
|
|
primitive->SetFilter(electronFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSMinKinEAtGeneration("minEkinPositron", j);
|
|
primitive->SetFilter(positronFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSTrackLength("trackLength", j);
|
|
primitive->SetFilter(epFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
primitive = new G4PSNofStep("nStep", j);
|
|
primitive->SetFilter(epFilter);
|
|
det->RegisterPrimitive(primitive);
|
|
|
|
if (j == 0) {
|
|
SetSensitiveDetector(fLayerLogical[i], det);
|
|
}
|
|
else {
|
|
SetSensitiveDetector(fGapLogical[i], det);
|
|
}
|
|
}
|
|
}
|
|
G4SDManager::GetSDMpointer()->SetVerboseLevel(0);
|
|
}
|
|
|
|
void RE06DetectorConstruction::PrintCalorParameters() const
|
|
{
|
|
G4cout << "--------------------------------------------------------" << G4endl;
|
|
if (fSerial) {
|
|
G4cout << " Calorimeters are placed in serial." << G4endl;
|
|
}
|
|
else {
|
|
G4cout << " Calorimeters are placed in parallel." << G4endl;
|
|
}
|
|
G4cout << " Absorber is made of " << fAbsorberMaterial->GetName() << G4endl << " Gap is made of "
|
|
<< fGapMaterial->GetName() << G4endl
|
|
<< "--------------------------------------------------------" << G4endl;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::SetAbsorberMaterial(G4String materialChoice)
|
|
{
|
|
// search the material by its name
|
|
G4Material* pttoMaterial = G4Material::GetMaterial(materialChoice);
|
|
if (pttoMaterial) {
|
|
fAbsorberMaterial = pttoMaterial;
|
|
if (fConstructed)
|
|
for (size_t i = 0; i < 3; i++) {
|
|
fCalorLogical[i]->SetMaterial(fAbsorberMaterial);
|
|
fLayerLogical[i]->SetMaterial(fAbsorberMaterial);
|
|
}
|
|
G4RunManager::GetRunManager()->GeometryHasBeenModified();
|
|
if (GetVerboseLevel() > 1) {
|
|
PrintCalorParameters();
|
|
}
|
|
}
|
|
else {
|
|
G4cerr << materialChoice << " is not defined. - Command is ignored." << G4endl;
|
|
}
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
G4String RE06DetectorConstruction::GetAbsorberMaterial() const
|
|
{
|
|
return fAbsorberMaterial->GetName();
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::SetGapMaterial(G4String materialChoice)
|
|
{
|
|
// search the material by its name
|
|
G4Material* pttoMaterial = G4Material::GetMaterial(materialChoice);
|
|
if (pttoMaterial) {
|
|
fGapMaterial = pttoMaterial;
|
|
if (fConstructed)
|
|
for (size_t i = 0; i < 3; i++) {
|
|
fGapLogical[i]->SetMaterial(fGapMaterial);
|
|
}
|
|
G4RunManager::GetRunManager()->GeometryHasBeenModified();
|
|
if (GetVerboseLevel() > 1) {
|
|
PrintCalorParameters();
|
|
}
|
|
}
|
|
else {
|
|
G4cerr << materialChoice << " is not defined. - Command is ignored." << G4endl;
|
|
}
|
|
}
|
|
|
|
G4String RE06DetectorConstruction::GetGapMaterial() const
|
|
{
|
|
return fGapMaterial->GetName();
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::SetSerialGeometry(G4bool serial)
|
|
{
|
|
if (fSerial == serial) return;
|
|
fSerial = serial;
|
|
RE06PrimaryGeneratorAction* gen =
|
|
(RE06PrimaryGeneratorAction*)(G4RunManager::GetRunManager()->GetUserPrimaryGeneratorAction());
|
|
if (gen) gen->SetSerial(fSerial);
|
|
if (!fConstructed) return;
|
|
for (G4int i = 0; i < 3; i++) {
|
|
if (fSerial) {
|
|
fCalorPhysical[i]->SetTranslation(G4ThreeVector(0., 0., G4double(i - 1) * 2. * m));
|
|
}
|
|
else {
|
|
fCalorPhysical[i]->SetTranslation(G4ThreeVector(0., G4double(i - 1) * m, 0.));
|
|
}
|
|
}
|
|
((RE06ParallelWorld*)GetParallelWorld(0))->SetSerialGeometry(serial);
|
|
G4RunManager::GetRunManager()->GeometryHasBeenModified();
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::SetNumberOfLayers(G4int nl)
|
|
{
|
|
fNumberOfLayers = nl;
|
|
fLayerThickness = fTotalThickness / fNumberOfLayers;
|
|
if (!fConstructed) return;
|
|
|
|
fLayerSolid->SetZHalfLength(fLayerThickness / 2.);
|
|
fGapSolid->SetZHalfLength(fLayerThickness / 4.);
|
|
for (size_t i = 0; i < 3; i++) {
|
|
fCalorLogical[i]->RemoveDaughter(fLayerPhysical[i]);
|
|
delete fLayerPhysical[i];
|
|
fLayerPhysical[i] = new G4PVReplica(fCalName[i] + "_Layer", fLayerLogical[i], fCalorLogical[i],
|
|
kZAxis, fNumberOfLayers, fLayerThickness);
|
|
fGapPhysical[i]->SetTranslation(G4ThreeVector(0., 0., fLayerThickness / 4.));
|
|
}
|
|
G4RunManager::GetRunManager()->GeometryHasBeenModified();
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
|
|
void RE06DetectorConstruction::AddMaterial()
|
|
{
|
|
static G4bool isAdded = false;
|
|
|
|
if (isAdded) return;
|
|
|
|
G4String name, symbol; // a=mass of a mole;
|
|
G4double a, z, density; // z=mean number of protons;
|
|
|
|
G4int ncomponents, natoms;
|
|
|
|
//
|
|
// define simple materials
|
|
//
|
|
|
|
new G4Material(name = "Copper", z = 29., a = 63.546 * g / mole, density = 8.96 * g / cm3);
|
|
new G4Material(name = "Tungsten", z = 74., a = 183.84 * g / mole, density = 19.3 * g / cm3);
|
|
|
|
G4Element* C = G4Element::GetElement("Carbon");
|
|
G4Element* O = G4Element::GetElement("Oxygen");
|
|
|
|
G4Material* CO2 = new G4Material("CarbonicGas", density = 27. * mg / cm3, ncomponents = 2,
|
|
kStateGas, 325. * kelvin, 50. * atmosphere);
|
|
CO2->AddElement(C, natoms = 1);
|
|
CO2->AddElement(O, natoms = 2);
|
|
|
|
isAdded = true;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|