Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-01 07:50:48

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 /// \file DetectorConstruction.cc
0027 /// \brief Implementation of the DetectorConstruction class
0028 
0029 #include "DetectorConstruction.hh"
0030 
0031 #include "DetectorMessenger.hh"
0032 
0033 #include "G4Box.hh"
0034 #include "G4GeometryManager.hh"
0035 #include "G4LogicalVolume.hh"
0036 #include "G4LogicalVolumeStore.hh"
0037 #include "G4Material.hh"
0038 #include "G4NistManager.hh"
0039 #include "G4PVPlacement.hh"
0040 #include "G4PVReplica.hh"
0041 #include "G4PhysicalConstants.hh"
0042 #include "G4PhysicalVolumeStore.hh"
0043 #include "G4RunManager.hh"
0044 #include "G4SolidStore.hh"
0045 #include "G4SystemOfUnits.hh"
0046 #include "G4UnitsTable.hh"
0047 
0048 #include <iomanip>
0049 
0050 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0051 
0052 DetectorConstruction::DetectorConstruction()
0053 {
0054   for (G4int i = 0; i < kMaxAbsor; ++i) {
0055     fAbsorMaterial[i] = nullptr;
0056     fAbsorThickness[i] = 0.0;
0057     fSolidAbsor[i] = nullptr;
0058     fLogicAbsor[i] = nullptr;
0059     fPhysiAbsor[i] = nullptr;
0060   }
0061 
0062   // default parameter values of the calorimeter
0063   fNbOfAbsor = 2;
0064   fAbsorThickness[1] = 36 * mm;
0065   fAbsorThickness[2] = 4 * mm;
0066   fNbOfLayers = 50;
0067   fCalorSizeYZ = 1.5 * m;
0068   ComputeCalorParameters();
0069 
0070   // materials
0071   DefineMaterials();
0072   SetWorldMaterial("Galactic");
0073   SetAbsorMaterial(1, "Iron");
0074   SetAbsorMaterial(2, "Scintillator");
0075 
0076   // create commands for interactive definition of the calorimeter
0077   fDetectorMessenger = new DetectorMessenger(this);
0078 }
0079 
0080 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0081 
0082 DetectorConstruction::~DetectorConstruction()
0083 {
0084   delete fDetectorMessenger;
0085 }
0086 
0087 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0088 
0089 void DetectorConstruction::DefineMaterials()
0090 {
0091   // This function illustrates the possible ways to define materials using
0092   // G4 database on G4Elements
0093   G4NistManager* manager = G4NistManager::Instance();
0094   manager->SetVerbose(0);
0095   //
0096   // define Elements
0097   //
0098   G4Element* H = manager->FindOrBuildElement(1);
0099   G4Element* C = manager->FindOrBuildElement(6);
0100   G4Element* O = manager->FindOrBuildElement(8);
0101   //
0102   // define an Element from isotopes, by relative abundance
0103   //
0104   G4int iz, n;  // iz=number of protons  in an isotope;
0105                 //  n=number of nucleons in an isotope;
0106   G4int ncomponents;
0107   G4double z, a;
0108   G4double abundance;
0109 
0110   G4Isotope* U5 = new G4Isotope("U235", iz = 92, n = 235, a = 235.01 * g / mole);
0111   G4Isotope* U8 = new G4Isotope("U238", iz = 92, n = 238, a = 238.03 * g / mole);
0112 
0113   G4Element* U = new G4Element("enriched Uranium", "U", ncomponents = 2);
0114   U->AddIsotope(U5, abundance = 90. * perCent);
0115   U->AddIsotope(U8, abundance = 10. * perCent);
0116 
0117   //
0118   // define simple materials
0119   //
0120   G4double density;
0121 
0122   new G4Material("liquidH2", z = 1., a = 1.008 * g / mole, density = 70.8 * mg / cm3);
0123   new G4Material("Aluminium", z = 13., a = 26.98 * g / mole, density = 2.700 * g / cm3);
0124   new G4Material("liquidArgon", z = 18, a = 39.948 * g / mole, density = 1.396 * g / cm3);
0125   new G4Material("Titanium", z = 22., a = 47.867 * g / mole, density = 4.54 * g / cm3);
0126   new G4Material("Iron", z = 26., a = 55.85 * g / mole, density = 7.870 * g / cm3);
0127   new G4Material("Copper", z = 29., a = 63.55 * g / mole, density = 8.960 * g / cm3);
0128   new G4Material("Tungsten", z = 74., a = 183.85 * g / mole, density = 19.30 * g / cm3);
0129   new G4Material("Gold", z = 79., a = 196.97 * g / mole, density = 19.32 * g / cm3);
0130   new G4Material("Lead", z = 82., a = 207.20 * g / mole, density = 11.35 * g / cm3);
0131   new G4Material("Uranium", z = 92., a = 238.03 * g / mole, density = 18.95 * g / cm3);
0132 
0133   //
0134   // define a material from elements.   case 1: chemical molecule
0135   //
0136   G4int natoms;
0137 
0138   G4Material* H2O = new G4Material("Water", density = 1.000 * g / cm3, ncomponents = 2);
0139   H2O->AddElement(H, natoms = 2);
0140   H2O->AddElement(O, natoms = 1);
0141   H2O->GetIonisation()->SetMeanExcitationEnergy(78.0 * eV);
0142   H2O->SetChemicalFormula("H_2O");
0143 
0144   G4Material* CH = new G4Material("Polystyrene", density = 1.032 * g / cm3, ncomponents = 2);
0145   CH->AddElement(C, natoms = 1);
0146   CH->AddElement(H, natoms = 1);
0147 
0148   G4Material* Sci = new G4Material("Scintillator", density = 1.032 * g / cm3, ncomponents = 2);
0149   Sci->AddElement(C, natoms = 9);
0150   Sci->AddElement(H, natoms = 10);
0151 
0152   Sci->GetIonisation()->SetBirksConstant(0.126 * mm / MeV);
0153 
0154   //
0155   // examples of gas in non STP conditions
0156   //
0157   G4double temperature, pressure;
0158 
0159   G4Material* CO2 =
0160     new G4Material("CarbonicGas", density = 27. * mg / cm3, ncomponents = 2, kStateGas,
0161                    temperature = 325. * kelvin, pressure = 50. * atmosphere);
0162   CO2->AddElement(C, natoms = 1);
0163   CO2->AddElement(O, natoms = 2);
0164 
0165   new G4Material("ArgonGas", z = 18, a = 39.948 * g / mole, density = 1.782 * mg / cm3, kStateGas,
0166                  273.15 * kelvin, 1 * atmosphere);
0167   //
0168   // example of vacuum
0169   //
0170   density = universe_mean_density;  // from PhysicalConstants.h
0171   pressure = 3.e-18 * pascal;
0172   temperature = 2.73 * kelvin;
0173   new G4Material("Galactic", z = 1., a = 1.008 * g / mole, density, kStateGas, temperature,
0174                  pressure);
0175 
0176   //  G4cout << *(G4Material::GetMaterialTable()) << G4endl;
0177 }
0178 
0179 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0180 
0181 G4Material* DetectorConstruction::MaterialWithSingleIsotope(G4String name, G4String symbol,
0182                                                             G4double density, G4int Z, G4int A)
0183 {
0184   // define a material from an isotope
0185   //
0186   G4int ncomponents;
0187   G4double abundance, massfraction;
0188 
0189   G4Isotope* isotope = new G4Isotope(symbol, Z, A);
0190 
0191   G4Element* element = new G4Element(name, symbol, ncomponents = 1);
0192   element->AddIsotope(isotope, abundance = 100. * perCent);
0193 
0194   G4Material* material = new G4Material(name, density, ncomponents = 1);
0195   material->AddElement(element, massfraction = 100. * perCent);
0196 
0197   return material;
0198 }
0199 
0200 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0201 
0202 void DetectorConstruction::ComputeCalorParameters()
0203 {
0204   // Compute derived parameters of the calorimeter
0205   fLayerThickness = 0.;
0206   for (G4int iAbs = 1; iAbs <= fNbOfAbsor; iAbs++) {
0207     fLayerThickness += fAbsorThickness[iAbs];
0208   }
0209   fCalorThickness = fNbOfLayers * fLayerThickness;
0210   fWorldSizeX = 1.2 * fCalorThickness;
0211   fWorldSizeYZ = 1.2 * fCalorSizeYZ;
0212 }
0213 
0214 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0215 
0216 G4VPhysicalVolume* DetectorConstruction::Construct()
0217 {
0218   if (fPhysiWorld) {
0219     return fPhysiWorld;
0220   }
0221   // complete the Calor parameters definition
0222   ComputeCalorParameters();
0223 
0224   //
0225   // World
0226   //
0227   fSolidWorld = new G4Box("World",  // its name
0228                           fWorldSizeX / 2, fWorldSizeYZ / 2, fWorldSizeYZ / 2);  // its size
0229 
0230   fLogicWorld = new G4LogicalVolume(fSolidWorld,  // its solid
0231                                     fWorldMaterial,  // its material
0232                                     "World");  // its name
0233 
0234   fPhysiWorld = new G4PVPlacement(0,  // no rotation
0235                                   G4ThreeVector(),  // at (0,0,0)
0236                                   fLogicWorld,  // its fLogical volume
0237                                   "World",  // its name
0238                                   0,  // its mother  volume
0239                                   false,  // no boolean operation
0240                                   0);  // copy number
0241   //
0242   // Calorimeter
0243   //
0244 
0245   fSolidCalor = new G4Box("Calorimeter", fCalorThickness / 2, fCalorSizeYZ / 2, fCalorSizeYZ / 2);
0246 
0247   fLogicCalor = new G4LogicalVolume(fSolidCalor, fWorldMaterial, "Calorimeter");
0248 
0249   fPhysiCalor = new G4PVPlacement(0,  // no rotation
0250                                   G4ThreeVector(),  // at (0,0,0)
0251                                   fLogicCalor,  // its fLogical volume
0252                                   "Calorimeter",  // its name
0253                                   fLogicWorld,  // its mother  volume
0254                                   false,  // no boolean operation
0255                                   0);  // copy number
0256 
0257   //
0258   // Layers
0259   //
0260 
0261   fSolidLayer = new G4Box("Layer", fLayerThickness / 2, fCalorSizeYZ / 2, fCalorSizeYZ / 2);
0262 
0263   fLogicLayer = new G4LogicalVolume(fSolidLayer, fWorldMaterial, "Layer");
0264   if (fNbOfLayers > 1) {
0265     fPhysiLayer =
0266       new G4PVReplica("Layer", fLogicLayer, fLogicCalor, kXAxis, fNbOfLayers, fLayerThickness);
0267   }
0268   else {
0269     fPhysiLayer =
0270       new G4PVPlacement(0, G4ThreeVector(), fLogicLayer, "Layer", fLogicCalor, false, 0);
0271   }
0272   //
0273   // Absorbers
0274   //
0275 
0276   G4double xfront = -0.5 * fLayerThickness;
0277   for (G4int k = 1; k <= fNbOfAbsor; ++k) {
0278     fSolidAbsor[k] = new G4Box("Absorber",  // its name
0279                                fAbsorThickness[k] / 2, fCalorSizeYZ / 2, fCalorSizeYZ / 2);
0280 
0281     fLogicAbsor[k] = new G4LogicalVolume(fSolidAbsor[k],  // its solid
0282                                          fAbsorMaterial[k],  // its material
0283                                          fAbsorMaterial[k]->GetName());
0284 
0285     G4double xcenter = xfront + 0.5 * fAbsorThickness[k];
0286     xfront += fAbsorThickness[k];
0287     fPhysiAbsor[k] = new G4PVPlacement(0, G4ThreeVector(xcenter, 0., 0.), fLogicAbsor[k],
0288                                        fAbsorMaterial[k]->GetName(), fLogicLayer, false,
0289                                        k);  // copy number
0290   }
0291 
0292   PrintCalorParameters();
0293 
0294   // always return the fPhysical World
0295   //
0296   return fPhysiWorld;
0297 }
0298 
0299 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0300 
0301 void DetectorConstruction::PrintCalorParameters()
0302 {
0303   G4int prec = 4, wid = prec + 2;
0304   G4int dfprec = G4cout.precision(prec);
0305 
0306   G4double totLength(0.), totRadl(0.), totNuclear(0.);
0307 
0308   G4cout << "\n-------------------------------------------------------------"
0309          << "\n ---> The calorimeter is " << fNbOfLayers << " layers of:";
0310   for (G4int i = 1; i <= fNbOfAbsor; ++i) {
0311     G4Material* material = fAbsorMaterial[i];
0312     G4double radl = material->GetRadlen();
0313     G4double nuclearl = material->GetNuclearInterLength();
0314     G4double sumThickness = fNbOfLayers * fAbsorThickness[i];
0315     G4double nbRadl = sumThickness / radl;
0316     G4double nbNuclearl = sumThickness / nuclearl;
0317     totLength += sumThickness;
0318     totRadl += nbRadl;
0319     totNuclear += nbNuclearl;
0320     G4cout << "\n   " << std::setw(12) << fAbsorMaterial[i]->GetName() << ": " << std::setw(wid)
0321            << G4BestUnit(fAbsorThickness[i], "Length") << "  --->  sum = " << std::setw(wid)
0322            << G4BestUnit(sumThickness, "Length") << " = " << std::setw(wid) << nbRadl << " Radl "
0323            << " = " << std::setw(wid) << nbNuclearl << " NuclearInteractionLength ";
0324   }
0325   G4cout << "\n\n                       total thickness = " << std::setw(wid)
0326          << G4BestUnit(totLength, "Length") << " = " << std::setw(wid) << totRadl << " Radl "
0327          << " = " << std::setw(wid) << totNuclear << " NuclearInteractionLength " << G4endl;
0328 
0329   G4cout << "                     transverse sizeYZ = " << std::setw(wid)
0330          << G4BestUnit(fCalorSizeYZ, "Length") << G4endl;
0331   G4cout << "-------------------------------------------------------------\n";
0332 
0333   G4cout << "\n" << fWorldMaterial << G4endl;
0334   for (G4int j = 1; j <= fNbOfAbsor; ++j) {
0335     G4cout << "\n" << fAbsorMaterial[j] << G4endl;
0336   }
0337   G4cout << "\n-------------------------------------------------------------\n";
0338 
0339   // restore default format
0340   G4cout.precision(dfprec);
0341 }
0342 
0343 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0344 
0345 void DetectorConstruction::SetWorldMaterial(const G4String& material)
0346 {
0347   // search the material by its name
0348   G4Material* pttoMaterial = G4NistManager::Instance()->FindOrBuildMaterial(material);
0349   if (pttoMaterial) {
0350     fWorldMaterial = pttoMaterial;
0351     if (fLogicWorld) {
0352       fLogicWorld->SetMaterial(fWorldMaterial);
0353       fLogicLayer->SetMaterial(fWorldMaterial);
0354       G4RunManager::GetRunManager()->PhysicsHasBeenModified();
0355     }
0356   }
0357 }
0358 
0359 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0360 
0361 void DetectorConstruction::SetNbOfLayers(G4int ival)
0362 {
0363   // set the number of Layers
0364   //
0365   if (ival < 1) {
0366     G4cout << "\n --->warning from SetfNbOfLayers: " << ival
0367            << " must be at least 1. Command refused" << G4endl;
0368     return;
0369   }
0370   fNbOfLayers = ival;
0371 }
0372 
0373 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0374 
0375 void DetectorConstruction::SetNbOfAbsor(G4int ival)
0376 {
0377   // set the number of Absorbers
0378   //
0379   if (ival < 1 || ival > (kMaxAbsor - 1)) {
0380     G4cout << "\n ---> warning from SetfNbOfAbsor: " << ival << " must be at least 1 and and most "
0381            << kMaxAbsor - 1 << ". Command refused" << G4endl;
0382     return;
0383   }
0384   fNbOfAbsor = ival;
0385 }
0386 
0387 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0388 
0389 void DetectorConstruction::SetAbsorMaterial(G4int ival, const G4String& material)
0390 {
0391   // search the material by its name
0392   //
0393   if (ival > fNbOfAbsor || ival <= 0) {
0394     G4cout << "\n --->warning from SetAbsorMaterial: absor number " << ival
0395            << " out of range. Command refused" << G4endl;
0396     return;
0397   }
0398 
0399   G4Material* pttoMaterial = G4NistManager::Instance()->FindOrBuildMaterial(material);
0400   if (pttoMaterial) {
0401     fAbsorMaterial[ival] = pttoMaterial;
0402     if (fLogicAbsor[ival]) {
0403       fLogicAbsor[ival]->SetMaterial(pttoMaterial);
0404       G4RunManager::GetRunManager()->PhysicsHasBeenModified();
0405     }
0406   }
0407 }
0408 
0409 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0410 
0411 void DetectorConstruction::SetAbsorThickness(G4int ival, G4double val)
0412 {
0413   // change Absorber thickness
0414   //
0415   if (ival > fNbOfAbsor || ival <= 0) {
0416     G4cout << "\n --->warning from SetAbsorThickness: absor number " << ival
0417            << " out of range. Command refused" << G4endl;
0418     return;
0419   }
0420   if (val <= DBL_MIN) {
0421     G4cout << "\n --->warning from SetAbsorThickness: thickness " << val
0422            << " out of range. Command refused" << G4endl;
0423     return;
0424   }
0425   fAbsorThickness[ival] = val;
0426 }
0427 
0428 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0429 
0430 void DetectorConstruction::SetCalorSizeYZ(G4double val)
0431 {
0432   // change the transverse size
0433   //
0434   if (val <= DBL_MIN) {
0435     G4cout << "\n --->warning from SetfCalorSizeYZ: thickness " << val
0436            << " out of range. Command refused" << G4endl;
0437     return;
0438   }
0439   fCalorSizeYZ = val;
0440 }
0441 
0442 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0443 
0444 #include "G4AutoDelete.hh"
0445 #include "G4GlobalMagFieldMessenger.hh"
0446 
0447 void DetectorConstruction::ConstructSDandField()
0448 {
0449   if (fFieldMessenger.Get() == nullptr) {
0450     // Create global magnetic field messenger.
0451     // Uniform magnetic field is then created automatically if
0452     // the field value is not zero.
0453     G4ThreeVector fieldValue = G4ThreeVector();
0454     G4GlobalMagFieldMessenger* msg = new G4GlobalMagFieldMessenger(fieldValue);
0455     // msg->SetVerboseLevel(1);
0456     G4AutoDelete::Register(msg);
0457     fFieldMessenger.Put(msg);
0458   }
0459 }
0460 
0461 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......