CLARION2_GEANT4/CloverDetectorConstruction.cc
2022-10-16 02:45:01 -04:00

401 lines
15 KiB
C++

#include "CloverDetectorConstruction.hh"
#include "CloverCrystalSD.hh"
#include "Detector_Parameters.hh"
#include "G4Material.hh"
#include "G4NistManager.hh"
#include "G4Box.hh"
#include "G4Tubs.hh"
#include "G4Sphere.hh"
#include "G4Trd.hh"
#include "G4UnionSolid.hh"
#include "G4IntersectionSolid.hh"
#include "G4SubtractionSolid.hh"
#include "G4LogicalVolume.hh"
#include "G4PVPlacement.hh"
#include "G4PVReplica.hh"
#include "G4GlobalMagFieldMessenger.hh"
#include "G4AutoDelete.hh"
#include "G4RotationMatrix.hh"
#include "G4SDManager.hh"
#include "G4VisAttributes.hh"
#include "G4Colour.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include <vector>
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ThreadLocal
G4GlobalMagFieldMessenger* CloverDetectorConstruction::fMagFieldMessenger = 0;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
CloverDetectorConstruction::CloverDetectorConstruction()
: G4VUserDetectorConstruction(),
fNumOfCrystal(0),
fLogicCrystal(NULL), fCrystalMaterial(NULL),
fCheckOverlaps(true)
{
fNumOfCrystal = Crystal_Num; //also need to change the fNDet in CloverEventAction.cc
fLogicCrystal = new G4LogicalVolume* [fNumOfCrystal];
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
CloverDetectorConstruction::~CloverDetectorConstruction()
{
delete [] fLogicCrystal;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4VPhysicalVolume* CloverDetectorConstruction::Construct()
{
// Define materials
DefineMaterials();
// Define volumes
return DefineVolumes();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void CloverDetectorConstruction::DefineMaterials()
{
// Lead material defined using NIST Manager
auto nistManager = G4NistManager::Instance();
// Vacuum
new G4Material("Galactic", 1., 1.01*g/mole, universe_mean_density, kStateGas, 2.73*kelvin, 3.e-18*pascal);
// Air
nistManager->FindOrBuildMaterial("G4_AIR");
// Iron
nistManager->FindOrBuildMaterial("G4_Fe");
// Aluminium
nistManager->FindOrBuildMaterial("G4_Al");
// Ge
fCrystalMaterial = nistManager->FindOrBuildMaterial("G4_Ge");
// Print materials
G4cout << *(G4Material::GetMaterialTable()) << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4VPhysicalVolume* CloverDetectorConstruction::DefineVolumes()
{
// Geometry parameters
G4double crystalLength = 8.*cm;
G4double crystalRadius = 25.*mm;
G4double crystalZPos = Radius*mm + crystalLength/2.; //distance to target + distance to center of crystals.;
G4double cutXY = 46.0 * mm;
G4double worldSizeZ = 2*(crystalLength + crystalZPos);
G4double worldSizeXY = worldSizeZ;
/*
//pipe
G4double pipeOuterRadius = 100/2.* mm;
G4double pipeWallThickness = 5 * mm;
G4double pipeLength = 70* mm;
G4double pipeZPos = 0.*cm;
*/
//spherical chamber
G4double chamberOuterRadius = 150/2.* mm;
G4double chamberWallThickness = 5 * mm;
G4double chamberInnerRadius = chamberOuterRadius - chamberWallThickness;
G4double chamberZPos = 0.*cm;
//Clover casing
G4double caseXYInner = 2*(cutXY + 1.0) * mm;
G4double caseZInner = crystalLength/2 + crystalLength + 10*mm;
G4double caseXYWallThickness = 3.0 * mm;
G4double caseZWallThickness = 3.0 * mm;
//BGO Detector
G4double bgoXYInner = 10*mm + 2*(cutXY + 1.0) * mm;
G4double bgoZInner = crystalLength/2 + 4 * mm + crystalLength + 15*mm;
G4double bgoXYWallThickness = 103.5 * mm; //from schematic
G4double bgoanglecut0 = 53 * mm ;
G4double zbgo0 = 178 * mm;
G4double bgoanglecut1 = 24.935 * mm;
G4double zbgo1 = 80*mm;
G4double bgoanglecut2 = 10 *mm ;
G4double zbgo2 = 20*mm;
// Get materials
auto backgroundMaterial = G4Material::GetMaterial("G4_AIR");
//auto backgroundMaterial = G4Material::GetMaterial("Galactic");
// World
auto worldS = new G4Box("World", worldSizeXY/2, worldSizeXY/2, worldSizeZ);
auto worldLV = new G4LogicalVolume( worldS, backgroundMaterial, "World");
auto worldPV = new G4PVPlacement( 0, // no rotation
G4ThreeVector(), // at (0,0,0)
worldLV, // its logical volume
"World", // its name
0, // its mother volume
false, // no boolean operation
0, // copy number
fCheckOverlaps); // checking overlaps
worldLV->SetVisAttributes (G4VisAttributes::GetInvisible());
// vaccum Pipe
// G4Tubs * pipe = new G4Tubs("pipe", pipeOuterRadius - pipeWallThickness , pipeOuterRadius, pipeLength, 0, 360*degree);
// G4Tubs * pipe0 = new G4Tubs("pipe0", 0 , pipeOuterRadius, pipeLength, 0, 360*degree);
G4Sphere *chamber = new G4Sphere("chamber",chamberInnerRadius,chamberOuterRadius,0,2*pi,0,pi);
G4RotationMatrix * rotX = new G4RotationMatrix(); rotX->rotateX(90*degree);
G4RotationMatrix * rotY = new G4RotationMatrix(); rotY->rotateY(90*degree);
G4LogicalVolume * chamberLV = new G4LogicalVolume(chamber, G4Material::GetMaterial("G4_Fe"),"targetchamber");
new G4PVPlacement( 0, // no rotation
G4ThreeVector(0, 0, chamberZPos), // at (0,0,0)
chamberLV, // its logical volume
"targetchamber", // its name
worldLV, // its mother volume
false, // no boolean operation
0, // copy number
fCheckOverlaps); // checking overlaps
chamberLV->SetVisAttributes(new G4VisAttributes(G4Colour(1.0,1.0,1.0)));
// Crystals
G4VisAttributes * crystalVisAtt= new G4VisAttributes(G4Colour(0.5,0.5,1.0));
crystalVisAtt->SetVisibility(true);
//define crystal shapes
G4Tubs * base = new G4Tubs("base", 0, crystalRadius, crystalLength/2., 0, 360*degree);
G4Box * cut = new G4Box("cut", cutXY/2. , cutXY/2. , crystalLength/2. * 1.2);
G4IntersectionSolid * crystalS = new G4IntersectionSolid("HPGe", base, cut);
G4Box* case1 = new G4Box("case1", caseXYInner/2., caseXYInner/2., caseZInner );
G4Box* case2 = new G4Box("case2", (caseXYInner + caseXYWallThickness)/2. , (caseXYInner + caseXYWallThickness)/2., caseZInner + caseZWallThickness*2.);
G4SubtractionSolid * casing = new G4SubtractionSolid("casing", case2, case1);
G4Box* bgo1 = new G4Box("bgo1", bgoXYInner/2., bgoXYInner/2., bgoZInner +zbgo1);
G4Trd* bgo2 = new G4Trd("bgo2", (bgoXYInner+ bgoXYWallThickness)/2. - bgoanglecut1 ,(bgoXYInner+ bgoXYWallThickness)/2.
, (bgoXYInner + bgoXYWallThickness)/2. - bgoanglecut1, (bgoXYInner + bgoXYWallThickness)/2., zbgo0/2);
G4Trd* bgo3 = new G4Trd("bgo3", (bgoXYInner+ bgoXYWallThickness)/2. - bgoanglecut0 + bgoanglecut2,(bgoXYInner+ bgoXYWallThickness)/2. - bgoanglecut1
, (bgoXYInner + bgoXYWallThickness)/2. - bgoanglecut0 + bgoanglecut2, (bgoXYInner + bgoXYWallThickness)/2.- bgoanglecut1, zbgo1/2);
G4ThreeVector bgo3_v = G4ThreeVector(0.,0.,-zbgo0 + 50*mm);
G4RotationMatrix * bgo3_m = new G4RotationMatrix();
G4VSolid* bgo_u = new G4UnionSolid("bgo2 + bgo3",bgo2,bgo3,bgo3_m,bgo3_v);
//G4Box* bgo2 = new G4Box("bgo2", (bgoXYInner+ bgoXYWallThickness)/2., (bgoXYInner + bgoXYWallThickness)/2., bgoZInner + bgoZWallThickness*2.);
G4Trd* bgowindow = new G4Trd("bgowindow", (bgoXYInner+ bgoXYWallThickness)/2. - bgoanglecut0 ,(bgoXYInner+ bgoXYWallThickness)/2. - bgoanglecut0 +bgoanglecut2
, (bgoXYInner + bgoXYWallThickness)/2. - bgoanglecut0, (bgoXYInner + bgoXYWallThickness)/2. -bgoanglecut0 +bgoanglecut2, zbgo2/2);
G4SubtractionSolid * bgo = new G4SubtractionSolid("bgo", bgo_u, bgo1);
// creating the subtraction solid that will form the actual bgo sheild.
double dTheta,dPsi,zmod;
for( G4int i = 0 ; i < fNumOfCrystal ; i++){
G4String name = "HPGe"+ std::to_string(i);
G4cout << " crystal name : " << name << G4endl;
G4double phi = 360./4. * degree;
G4double rho = 0;
rho = (cutXY/2 + 0.3* mm) / sin(phi/2.);
int iClover = i/4; //How to get each group of crystals.
int jCrystal = i%4; //How to renumber each group as 0,1,2,3.
fLogicCrystal[i] = new G4LogicalVolume(crystalS, fCrystalMaterial, "CrystalLV");
auto caseLV = new G4LogicalVolume * [fNumOfCrystal/4];
auto bgoLV = new G4LogicalVolume * [fNumOfCrystal/4];
auto bgowindowLV = new G4LogicalVolume * [fNumOfCrystal/4];
fLogicCrystal[i]->SetVisAttributes(crystalVisAtt);
if(int j = iClover){
dTheta = Clover_Location[j][1];
dPsi = Clover_Location[j][2];
zmod = Clover_Location[j][3];
}
G4ThreeVector pos = G4ThreeVector(rho * cos(jCrystal* phi + phi/2.), rho * sin(jCrystal * phi + phi/2.), crystalZPos+zmod);
// if(iClover != DetNum){return 0;}
G4ThreeVector case_pos = G4ThreeVector(0,0,88*mm+crystalZPos); //The crystalZpos is the radius of the detector,
//bgo uses an identical rotation matrix as the case,
//you can also add in zmod if you want to shift the shielding.
G4ThreeVector bgo_pos = G4ThreeVector(0,0,115*mm+crystalZPos);
G4ThreeVector bgowindow_pos = G4ThreeVector(0,0,-63*mm + crystalZPos);
//Set rotation matrix settings for clovers.
G4RotationMatrix * bgowindowmat = new G4RotationMatrix();
G4RotationMatrix * bgomat = new G4RotationMatrix();
G4RotationMatrix * rotmat = new G4RotationMatrix();
G4RotationMatrix * crystalmat= new G4RotationMatrix();
//x = sin(theta)cos(phi) || y = sin(theta)sin(phi) || z = cos(theta)
for(int j = 0; j <= iClover;j++){
if(j == iClover){
// rotation matrix must undo the operations you perform with the position vector.
bgowindowmat->rotateZ(-dPsi*degree);
bgowindowmat->rotateX(-dTheta*degree);
bgomat->rotateZ(-dPsi*degree);
bgomat->rotateX(-dTheta*degree);
rotmat->rotateZ(-dPsi*degree);
rotmat->rotateX(-dTheta*degree);
crystalmat->rotateZ(-dPsi*degree);
crystalmat->rotateX(-dTheta*degree);
//rotate position vector based on iClover.
pos.rotateX(dTheta*degree);
pos.rotateZ(dPsi *degree);
case_pos.rotateX(dTheta *degree);
case_pos.rotateZ(dPsi*degree);
bgo_pos.rotateX(dTheta *degree);
bgo_pos.rotateZ(dPsi*degree);
bgowindow_pos.rotateX(dTheta *degree);
bgowindow_pos.rotateZ(dPsi*degree);
}
}
new G4PVPlacement( crystalmat, // orientation matrix
pos, // its position vector
fLogicCrystal[i], // its logical volume
name, // its name
worldLV, // its mother volume
false, // no boolean operation
i, // copy number
fCheckOverlaps); // checking overlaps
if( jCrystal == 0 ) {
caseLV[iClover] = new G4LogicalVolume(casing, G4Material::GetMaterial("G4_Al"), "Case");
bgoLV[iClover] = new G4LogicalVolume(bgo , G4Material::GetMaterial("G4_Al"), "BGO ");
bgowindowLV[iClover] = new G4LogicalVolume(bgowindow, G4Material::GetMaterial("G4_Al"), "BGO WINDOW ");
new G4PVPlacement( rotmat , // case orientation
case_pos, // case location
caseLV[i/4], // its logical volume
"Casing", // its name
worldLV, // its mother volume
false, // no boolean operation
iClover, // copy number
fCheckOverlaps); // checking overlaps
new G4PVPlacement( bgomat , // bgo orientation
bgo_pos, // bgo location
bgoLV[i/4], // its logical volume
"Bgo", // its name
worldLV, // its mother volume
false, // no boolean operation
iClover, // copy number
fCheckOverlaps); // checking overlaps
new G4PVPlacement( bgowindowmat , // bgo orientation
bgowindow_pos, // bgo location
bgowindowLV[i/4], // its logical volume
"Bgowindow", // its name
worldLV, // its mother volume
false, // no boolean operation
iClover, // copy number
fCheckOverlaps); // checking overlaps
caseLV[iClover]->SetVisAttributes(new G4VisAttributes(G4Colour(1.0,1.0,0.0)));
bgoLV[iClover]->SetVisAttributes(new G4VisAttributes(G4Colour(0.,1.0,0.0)));
bgowindowLV[iClover]->SetVisAttributes(new G4VisAttributes(G4Colour(0.0,1.0,1.0)));
}
//Set a i+1%4 for each
//
}
// Al casing
// Always return the physical World
return worldPV;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void CloverDetectorConstruction::ConstructSDandField()
{
G4cout << "********************* CloverDetectorConstruction::ConstructSDandField() " << G4endl;
G4SDManager::GetSDMpointer()->SetVerboseLevel(1);
// Sensitive detectors
CloverCrystalSD * crystalSD = new CloverCrystalSD("Crystal", "CrystalHitsCollection", fNumOfCrystal);
G4SDManager::GetSDMpointer()->AddNewDetector(crystalSD);
//Set crystalSD to all logical volumn under the same name of "CrystalLV"
SetSensitiveDetector("CrystalLV",crystalSD, true);
// Create global magnetic field messenger.
// Uniform magnetic field is then created automatically if
// the field value is not zero.
G4ThreeVector fieldValue;
fMagFieldMessenger = new G4GlobalMagFieldMessenger(fieldValue);
fMagFieldMessenger->SetVerboseLevel(1);
// Register the field messenger for deleting
G4AutoDelete::Register(fMagFieldMessenger);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......