diff --git a/include/VKBetaDetector.hh b/include/VKBetaDetector.hh index 06b846dba9e7a5386a190d1818ad751132478e90..8c2c8da7c2ca76fffe82c6913fb3978b55369204 100644 --- a/include/VKBetaDetector.hh +++ b/include/VKBetaDetector.hh @@ -44,8 +44,7 @@ class VKBetaDetector : public G4PVPlacement public: /* - * Construct the main components of the Siegbahn-Slätis magnet: - * Copper coils, outer iron walls and inner brass surface. + * Construct Scionix plastic scintillator v1. * @param pRot Orientation of the detector. If pRot==0 the detector * is oriented along the symmetry axis (z axis) looking * in the direction of the source (negative z) diff --git a/include/VKBetaDetectorV2.hh b/include/VKBetaDetectorV2.hh new file mode 100644 index 0000000000000000000000000000000000000000..e90d6d28a17bfe456fe40e660b4271a043b1d0bc --- /dev/null +++ b/include/VKBetaDetectorV2.hh @@ -0,0 +1,142 @@ +// +// ******************************************************************** +// * 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. * +// ******************************************************************** +// +#ifndef VKBetaDetectorV2_H +#define VKBetaDetectorV2_H 1 + +#include "G4PVPlacement.hh" +#include "G4Box.hh" +#include "G4Tubs.hh" +#include "G4Sphere.hh" +#include "G4Material.hh" +#include "G4LogicalVolume.hh" +#include "G4OpticalSurface.hh" +#include "G4ThreeVector.hh" +#include "G4UnionSolid.hh" + +#include "VKDetectorConstruction.hh" +#include "VKMaterials.hh" + +class VKBetaDetectorV2 : public G4PVPlacement +{ + public: + + /* + * Construct Scionix plastic scintillator v2. + * @param pRot Orientation of the detector. If pRot==0 the detector + * is oriented along the symmetry axis (z axis) looking + * in the direction of the source (negative z) + * @param tlate Position of the front size of the detector (including coating) + * @param pMotherLogical Place detector inside this volume + * @param pMany Boolean operations + * @param pCopyNo Copy number + * @param pDetConstr Pointer to main detector constructor + */ + VKBetaDetectorV2(G4RotationMatrix *pRot, + const G4ThreeVector &tlate, + G4LogicalVolume *pMother_log, + G4bool pMany, + G4int pCopyNo, + const VKDetectorConstruction* pDetConstr); + + inline G4LogicalVolume* GetPhotocathodeLogVol() {return fPhotocathode_log;} + inline G4LogicalVolume* GetFrontLogVol() {return fFront_log;} + inline G4LogicalVolume* GetSignalLogVol() {return fSignal_log;} + inline G4LogicalVolume* GetVetoLogVol() {return fVeto_log;} + + const G4VPhysicalVolume* GetFrontPhysVol() const; + const G4VPhysicalVolume* GetSignalPhysVol() const; + const G4VPhysicalVolume* GetVetoPhysVol() const; + + inline const std::vector<G4ThreeVector>& GetSiPMPositions() const {return fSiPMPositions;} + + private: + + void VisAttributes(); + void SurfaceProperties(); + void SetDefaults(); + void ConstructCoatingSolid(G4double& displ); + + const VKDetectorConstruction* fDetConstr; + + // Materials + VKMaterials *fMaterials; + G4Material* fLabVacuum; + G4Material* fEJ200; + G4Material* fTeflon; + G4Material* fMylar; + G4Material* fGlass; + G4Material* fAluminium; + + // Dimensions + G4double fFrontDiameter; + G4double fFrontLength; + G4double fSignalDiameter; + G4double fSignalLength; + G4double fReflectorThickness; + G4double fVetoThickness; + G4double fVetoLength; + G4double fVetoEndcapLength; + G4double fWindowThickness; + G4double fContainerDiameter; + G4double fContainerLength; + G4double fSiPMDiameter; + G4double fSiPMLength; + + // Geometry + bool fCheckOverlaps; + G4LogicalVolume* fMother_log; + G4Tubs* fContainer_sol; + G4LogicalVolume* fContainer_log; + + G4Tubs* fFront_sol; + G4LogicalVolume* fFront_log; + + G4Tubs* fSignal_sol; + G4LogicalVolume* fSignal_log; + + G4UnionSolid* fVeto_sol; + G4LogicalVolume* fVeto_log; + + G4Tubs* fWindow_sol; + G4LogicalVolume* fWindow_log; + + G4UnionSolid* fCoating_sol; + G4LogicalVolume* fCoating_log; + + G4Tubs* fSiPM_sol; + G4LogicalVolume* fSiPM_log; + + G4Tubs* fPhotocathode_sol; + G4LogicalVolume* fPhotocathode_log; + + // Surface properties + G4double fRefl; + + // SiPM multiplicity and positions + std::vector<G4ThreeVector> fSiPMPositions; +}; + +#endif diff --git a/src/VKBetaDetectorV2.cpp b/src/VKBetaDetectorV2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a68baa30686db6328df31ac6b62ad1cb6791a48 --- /dev/null +++ b/src/VKBetaDetectorV2.cpp @@ -0,0 +1,482 @@ +// +// ******************************************************************** +// * 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. * +// ******************************************************************** +// +#include "globals.hh" + +#include "VKBetaDetectorV2.hh" +#include "VKUtil.hh" + +#include "G4LogicalSkinSurface.hh" +#include "G4LogicalBorderSurface.hh" +#include "G4SystemOfUnits.hh" +#include "G4PhysicalVolumeStore.hh" + +/* + * The beta detector consists of stacked, cylindrical FRONT + * and SIGNAL detectors surrounded by a cup-shaped active + * cosmic-ray VETO shield. + * All surfaces are assumed covered by 0.5 mm reflective coating + * (Teflon) except the entrance window (6 micron mylar) and the + * areas where the SiPMs are attached. + * + * Note that the SiPMs are modelled as PMTs. + * + * The dimensions are: + * + * FRONT + * - diameter: 45 mm + * - length: 5 mm + * + * SIGNAL + * - diameter: 45 mm + * - length: 40 mm + * + * VETO + * - inner diameter: 46 mm + * - outer diameter: 56 mm + * - length: 75 mm + * - thickness of end cap: 15 mm + */ + + +VKBetaDetectorV2::VKBetaDetectorV2(G4RotationMatrix *pRot, + const G4ThreeVector &tlate, + G4LogicalVolume *pMother_log, + G4bool pMany, + G4int pCopyNo, + const VKDetectorConstruction* pDetConstr) + + // Pass info to the G4PVPlacement constructor + : G4PVPlacement(pRot, + tlate, + CreateTemporaryLogicalVolume(), // <-- see VKUtil.cpp + "betaDetector", + pMother_log, + pMany, + pCopyNo), + fDetConstr(pDetConstr), + fMother_log(pMother_log) +{ + // Default dimensions + SetDefaults(); + + // List of materials + fMaterials = VKMaterials::GetInstance(); + + // Get materials + fLabVacuum = fMaterials -> GetMaterial("LABVACUUM"); + fEJ200 = fMaterials -> GetMaterial("G4_PLASTIC_SC_VINYLTOLUENE"); + fTeflon = fMaterials -> GetMaterial("G4_TEFLON"); + fMylar = fMaterials -> GetMaterial("G4_MYLAR"); + fGlass = G4Material::GetMaterial("GLASS"), + fAluminium = fMaterials -> GetMaterial("ALUMINIUM"); + + assert(fEJ200 != nullptr); + assert(fTeflon != nullptr); + assert(fMylar != nullptr); + assert(fGlass != nullptr); + assert(fAluminium != nullptr); + + // Initialize some variables + G4double innerRadius, outerRadius; + G4double displ; + G4ThreeVector pos; + G4Transform3D transform; + G4RotationMatrix doNotRotate; + doNotRotate.rotateX(0.); + G4int copyNo; + + + // -------------------------------------------- // + // (Imaginary) container // + // -------------------------------------------- // + + // *** All other volumes should fit inside this volume ! + + // solid + fContainer_sol = new G4Tubs("betaDetector_sol", 0., fContainerDiameter/2, + fContainerLength/2, 0.*deg, 360.*deg); + + // logical + fContainer_log = new G4LogicalVolume(fContainer_sol, fLabVacuum, "betaDetector_log"); + + + // ----------------------------------------------- // + // SIGNAL scintillator // + // ----------------------------------------------- // + + // solid + fSignal_sol = new G4Tubs("signal_sol", 0., fSignalDiameter/2, + fSignalLength/2, 0.*deg, 360.*deg); + + // logical + fSignal_log = new G4LogicalVolume(fSignal_sol, fEJ200, "signal_log"); + + // physical + displ = -(fContainerLength - fSignalLength)/2 + fReflectorThickness; + pos = G4ThreeVector(0, 0, displ); + new G4PVPlacement(0, pos, fSignal_log, "signal", fContainer_log, false, 0, fCheckOverlaps); + + + // ----------------------------------------------- // + // VETO scintillator // + // ----------------------------------------------- // + + innerRadius = fSignalDiameter/2 + fReflectorThickness; + outerRadius = innerRadius + fVetoThickness; + + // tube + G4Tubs* vetoTube_sol = new G4Tubs("vetoTube_sol", innerRadius, outerRadius, + fVetoLength/2, 0.*deg, 360.*deg); + // end cap + G4Tubs* vetoEndcap_sol = new G4Tubs("vetoEndcap_sol", 0., innerRadius, + fVetoEndcapLength/2, 0.*deg, 360.*deg); + // relative placement + displ = fVetoLength/2 - fVetoEndcapLength/2; + pos = G4ThreeVector(0, 0, displ); + transform = G4Transform3D(doNotRotate, pos); + + // create union + fVeto_sol = new G4UnionSolid("veto_sol", vetoTube_sol, vetoEndcap_sol, transform); + + // logical + fVeto_log = new G4LogicalVolume(fVeto_sol, fEJ200, "veto_log"); + + // physical + displ = -(fContainerLength - fVetoLength)/2 + fReflectorThickness; + pos = G4ThreeVector(0, 0, displ); + new G4PVPlacement(0, pos, fVeto_log, "veto", fContainer_log, false, 0, fCheckOverlaps); + + + // ----------------------------------------------- // + // Mylar window // + // ----------------------------------------------- // + + // solid + fWindow_sol = new G4Tubs("window_sol", 0., fSignalDiameter/2, + fWindowThickness/2, 0.*deg, 360.*deg); + + // logical + fWindow_log = new G4LogicalVolume(fWindow_sol, fMylar, "window_log"); + + // physical + displ = -(fContainerLength + fWindowThickness)/2 + fReflectorThickness; + pos = G4ThreeVector(0, 0, displ); + new G4PVPlacement(0, pos, fWindow_log, "window", fContainer_log, false, 0, fCheckOverlaps); + + + // ----------------------------------------------- // + // Reflective coating // + // ----------------------------------------------- // + + // solid + ConstructCoatingSolid(displ); + + // logical + fCoating_log = new G4LogicalVolume(fCoating_sol, fTeflon, "coating_log"); + + // physical + pos = G4ThreeVector(0, 0, displ); + new G4PVPlacement(0, pos, fCoating_log, "coating", fContainer_log, false, 0, fCheckOverlaps); + + + // ----------------------------------------------- // + // SiPMs (modelled as PMTs) // + // ----------------------------------------------- // + + // SiPM solid and logical volumes + fSiPM_sol = new G4Tubs("SiPM_sol", 0., fSiPMDiameter/2, fSiPMLength/2, 0.*deg, 360.*deg); + fSiPM_log = new G4LogicalVolume(fSiPM_sol, fGlass, "SiPM_log"); + + // Photocathode volumes + // + // The "photocathode" is a metal slab at the back of the glass that + // is only a very rough approximation of the real thing since it only + // absorbs or detects the photons based on the efficiency set below. + // + fPhotocathode_sol = new G4Tubs("photocathode_sol", 0., fSiPMDiameter/2, fSiPMLength/4, 0.*deg, 360.*deg); + fPhotocathode_log = new G4LogicalVolume(fPhotocathode_sol, fAluminium, "photocathode_log"); + pos = G4ThreeVector(0, 0, fSiPMLength/4); + new G4PVPlacement(0, pos, fPhotocathode_log, "photocathode", fSiPM_log, false, fCheckOverlaps); + + // Place one SiPM on the back side of the SIGNAL scintillator + displ = -(fContainerLength - fSiPMLength)/2 + fReflectorThickness + fSignalLength; + pos = G4ThreeVector(0, 0, displ); + copyNo = 0; + new G4PVPlacement(0, pos, fSiPM_log, "SiPM", fContainer_log, false, copyNo, fCheckOverlaps); + fSiPMPositions.push_back(pos); + + // Place another SiPM on the back side of the VETO scintillator + displ = -(fContainerLength - fSiPMLength)/2 + fReflectorThickness + fVetoLength; + pos = G4ThreeVector(0, 0, displ); + copyNo = 1; + new G4PVPlacement(0, pos, fSiPM_log, "SiPM", fContainer_log, false, copyNo, fCheckOverlaps); + fSiPMPositions.push_back(pos); + + // ***IMPORTANT*** + // VKEventAction::EndOfEventAction() assumes that there are only two SiPMs, with copyNo=0 + // attached to SIGNAL and copyNo=1 attached to VETO. If you wish to add more SiPMs, you + // must make the necessary changes in VKEventAction::EndOfEventAction(). + // Also check if changes need to be made to VKStackingAction::ClassifyNewTrack() and in + // VKRecorderRoot.cpp. + + // Visualization attributes + VisAttributes(); + + + // Surface properties + SurfaceProperties(); + + + // Set the logical volume + this -> SetLogicalVolume(fContainer_log); + + // Move the detector so that 'tlate' coincides with + // the front of the detector (including coating) + pos = tlate + G4ThreeVector (0, 0, fContainerLength/2); + this -> SetTranslation(pos); + + // Check for overlaps + if (fCheckOverlaps) this -> CheckOverlaps(); +} + + +void VKBetaDetectorV2::SetDefaults() +{ + // check for overlaps? + fCheckOverlaps = fDetConstr -> GetCheckOverlaps(); + + // dimensions + fSignalDiameter = 45*mm; + fSignalLength = 45*mm; + fReflectorThickness = 0.5*mm; + fVetoThickness = 5*mm; + fVetoLength = 75*mm; + fVetoEndcapLength = 15*mm; + fWindowThickness = 6*um; + + // PMT and Photocathode + fSiPMDiameter = 30*mm; + fSiPMLength = 10*mm; + + // deduce container size + fContainerDiameter = 2*(fSignalDiameter/2 + 2*fReflectorThickness + fVetoThickness); + fContainerLength = fVetoLength + fReflectorThickness + fSiPMLength; + + // coating reflectivity + fRefl = fDetConstr -> GetCoatingReflectivity(); +} + + +void VKBetaDetectorV2::VisAttributes() +{ + // signal + G4VisAttributes* signal_va = new G4VisAttributes(G4Colour(0.0, 0.0, 1.0)); // blue + signal_va->SetVisibility(true); + signal_va->SetForceSolid(true); + fSignal_log->SetVisAttributes(signal_va); + + // veto + G4VisAttributes* veto_va = new G4VisAttributes(G4Colour(0.5, 0.5, 0.5)); // gray + veto_va->SetVisibility(true); + veto_va->SetForceSolid(true); + fVeto_log->SetVisAttributes(veto_va); + +} + + +// +// Source: Geant4 LXe example +// +void VKBetaDetectorV2::SurfaceProperties() +{ + G4double ephoton[] = {7.0*eV, 7.14*eV}; + const G4int num = sizeof(ephoton)/sizeof(G4double); + + // + // Reflective coating + // + G4double reflectivity[] = {fRefl, fRefl}; + G4double efficiency[] = {0.0, 0.0}; + G4MaterialPropertiesTable* reflCoat_mpt = new G4MaterialPropertiesTable(); + reflCoat_mpt -> AddProperty("REFLECTIVITY", ephoton, reflectivity, num); + reflCoat_mpt -> AddProperty("EFFICIENCY", ephoton, efficiency, num); + // Create optical surface + G4OpticalSurface* reflCoatOptSurf = + new G4OpticalSurface("reflCoatOptSurf", unified, polished, dielectric_metal); + reflCoatOptSurf -> SetMaterialPropertiesTable(reflCoat_mpt); + + // + // Photocathode + // + G4double photocath_EFF[] = {1., 1.}; // Enables 'detection' of photons + G4double photocath_ReR[] = {1.92, 1.92}; + G4double photocath_ImR[] = {1.69, 1.69}; + G4MaterialPropertiesTable* photocath_mpt = new G4MaterialPropertiesTable(); + photocath_mpt -> AddProperty("EFFICIENCY", ephoton, photocath_EFF, num); + photocath_mpt -> AddProperty("REALRINDEX", ephoton, photocath_ReR, num); + photocath_mpt -> AddProperty("IMAGINARYRINDEX", ephoton, photocath_ImR, num); + // Create optical surface + G4OpticalSurface* photocathOptSurf = + new G4OpticalSurface("photocathOptSurf", glisur, polished, dielectric_metal); + photocathOptSurf -> SetMaterialPropertiesTable(photocath_mpt); + + // + // 6um Mylar window (same properties as Reflective coating) + // + G4double mylarRefl[] = {fRefl, fRefl}; //{0.3, 0.3}; + G4double mylarEff[] = {0.0, 0.0}; + G4MaterialPropertiesTable* mylarWindow_mpt = new G4MaterialPropertiesTable(); + mylarWindow_mpt -> AddProperty("REFLECTIVITY", ephoton, mylarRefl, num); + mylarWindow_mpt -> AddProperty("EFFICIENCY", ephoton, mylarEff, num); + // Create optical surface + G4OpticalSurface* mylarWindowOptSurf = + new G4OpticalSurface("mylarWindowOptSurf", unified, polished, dielectric_metal); + mylarWindowOptSurf -> SetMaterialPropertiesTable(mylarWindow_mpt); + + + // + // Create logical skin surfaces + // + // *** NB: Mylar window gets same properties as reflective coating + // + new G4LogicalSkinSurface("coating_surf", fCoating_log, reflCoatOptSurf); + new G4LogicalSkinSurface("window_surf", fWindow_log, mylarWindowOptSurf); + new G4LogicalSkinSurface("photocathode_surf", fPhotocathode_log, photocathOptSurf); +} + + +void VKBetaDetectorV2::ConstructCoatingSolid( G4double& displ ) +{ + // rotation, translation and transformation + G4double dz; + G4RotationMatrix doNotRotate; + doNotRotate.rotateX(0.); + G4ThreeVector translation; + G4Transform3D transform; + + // coating 1 + G4double r1min = fSignalDiameter/2; + G4double r1max = fSignalDiameter/2 + fReflectorThickness; + G4double l1 = fReflectorThickness + fVetoLength - fVetoEndcapLength; + G4Tubs* c1 = new G4Tubs("coating1_sol", r1min, r1max, l1/2, 0.*deg, 360.*deg); + + // this will determine placement of coating volumes relative to other volumes + displ = -(fContainerLength - l1)/2; + + // coating 2 + G4double r2min = fSiPMDiameter/2; + G4double r2max = r1min; + G4double l2 = fReflectorThickness; + G4Tubs* c2 = new G4Tubs("coating2_sol", r2min, r2max, l2/2, 0.*deg, 360.*deg); + + // relative placement of 1 and 2 + dz = (l2-l1)/2 + fSignalLength + l2; + translation = G4ThreeVector(0, 0, dz); + transform = G4Transform3D(doNotRotate, translation); + + // create union of 1 and 2 + fCoating_sol = new G4UnionSolid("coating12_sol", c1, c2, transform); + + // coating 3 + G4double r3min = 0.; + G4double r3max = r1min; + G4double l3 = fReflectorThickness; + G4Tubs* c3 = new G4Tubs("coating3_sol", r3min, r3max, l3/2, 0.*deg, 360.*deg); + + // relative placement of 1 and 3 + dz = (l1-l3)/2; + translation = G4ThreeVector(0, 0, dz); + transform = G4Transform3D(doNotRotate, translation); + + // create union of 12 and 3 + fCoating_sol = new G4UnionSolid("coating123_sol", fCoating_sol, c3, transform); + + // coating 4 + G4double r4min = r1max; + G4double r4max = r4min + fVetoThickness; + G4double l4 = fReflectorThickness; + G4Tubs* c4 = new G4Tubs("coating4_sol", r4min, r4max, l4/2, 0.*deg, 360.*deg); + + // relative placement of 1 and 4 + dz = (l4-l1)/2; + translation = G4ThreeVector(0, 0, dz); + transform = G4Transform3D(doNotRotate, translation); + + // create union of 123 and 4 + fCoating_sol = new G4UnionSolid("coating1234_sol", fCoating_sol, c4, transform); + + // coating 5 + G4double r5min = r4max; + G4double r5max = r5min + fReflectorThickness; + G4double l5 = fVetoLength + 2*fReflectorThickness; + G4Tubs* c5 = new G4Tubs("coating5_sol", r5min, r5max, l5/2, 0.*deg, 360.*deg); + + // relative placement of 1 and 5 + dz = (l5-l1)/2; + translation = G4ThreeVector(0, 0, dz); + transform = G4Transform3D(doNotRotate, translation); + + // create union of 1234 and 5 + fCoating_sol = new G4UnionSolid("coating12345_sol", fCoating_sol, c5, transform); + + // coating 6 + G4double r6min = fSiPMDiameter/2; + G4double r6max = r5min; + G4double l6 = fReflectorThickness; + G4Tubs* c6 = new G4Tubs("coating6_sol", r6min, r6max, l6/2, 0.*deg, 360.*deg); + + // relative placement of 1 and 6 + dz = (l1-l6)/2 + l5-l1; + translation = G4ThreeVector(0, 0, dz); + transform = G4Transform3D(doNotRotate, translation); + + // create union of 12345 and 6 + fCoating_sol = new G4UnionSolid("coating_sol", fCoating_sol, c6, transform); +} + + +const G4VPhysicalVolume* VKBetaDetectorV2::GetFrontPhysVol() const +{ + const G4PhysicalVolumeStore *physVolStore = + static_cast<const G4PhysicalVolumeStore*>(G4PhysicalVolumeStore::GetInstance()); + return physVolStore -> GetVolume("front", false); +} + + +const G4VPhysicalVolume* VKBetaDetectorV2::GetSignalPhysVol() const +{ + const G4PhysicalVolumeStore *physVolStore = + static_cast<const G4PhysicalVolumeStore*>(G4PhysicalVolumeStore::GetInstance()); + return physVolStore -> GetVolume("signal", false); +} + + +const G4VPhysicalVolume* VKBetaDetectorV2::GetVetoPhysVol() const +{ + const G4PhysicalVolumeStore *physVolStore = + static_cast<const G4PhysicalVolumeStore*>(G4PhysicalVolumeStore::GetInstance()); + return physVolStore -> GetVolume("veto", false); +}