diff --git a/ratdb/ENCAPSULATION.ratdb b/ratdb/ENCAPSULATION.ratdb new file mode 100644 index 00000000..3d860fc9 --- /dev/null +++ b/ratdb/ENCAPSULATION.ratdb @@ -0,0 +1,30 @@ +{ +name: "ENCAPSULATION", +index: "BUTTON_r7081pe", +run_range: [0, 0], + +construction: "hemisphere", +envelope_radius: 244.0, // should be large enough to fit all objects (>flange_rmax) +front_encapsulation_material: "acrylic_uvt_good", +rear_encapsulation_material: "acrylic_black", +flange_rmax: 243.0, // applies to acrylic and metal flange +encap_radius: 200.0, +encap_thickness: 8.0, +use_metal_flange: 1, +metal_flange_material: "stainless_steel", +metal_flange_dimensions: [ 220.0, 243.0, 4.0 ], // G4Tubs dimensions rmin, rmax, z +inside_encapsulation_material: "air", +use_optical_gel: 1, +optical_gel_material: "optical_grease", +optical_gel_sub_height: 150.0, // start from a dome full of gel of size encap_radius, e.g. height of ... +// gel dome left is (encap_radius - optical_gel_sub_height) +pmtposoffset: [ 0.0, 0.0, 98.0 ], +use_silica_bag: 1, +silica_bag_material: "acrylic_white", +silica_bag_dimensions: [ 18.0, 33.0, 3.0 ], // G4Box dimensions x, y, z +silica_bag_position: [ 0.0, 135.0, -74.0 ], // x, y, z +use_cable: 1, +cable_material: "acrylic_black", +cable_dimensions: [ 0.0, 6.5, 45.0 ], // G4Tubs dimensions rmin, rmax, z +cable_position: [ 0.0, 0.0, -152.0 ], // x, y, z +} diff --git a/src/geo/CMakeLists.txt b/src/geo/CMakeLists.txt index 9ff8b24f..b58becaa 100644 --- a/src/geo/CMakeLists.txt +++ b/src/geo/CMakeLists.txt @@ -64,6 +64,8 @@ add_library(geo OBJECT src/pmt/RevolutionPMTConstruction.cc src/pmt/ToroidalPMTConstruction.cc src/pmt/CylindricalPMTConstruction.cc + src/pmt/PMTEncapsulation.cc + src/pmt/HemisphereEncapsulation.cc ) # Set our include directories diff --git a/src/geo/include/RAT/HemisphereEncapsulation.hh b/src/geo/include/RAT/HemisphereEncapsulation.hh new file mode 100644 index 00000000..bc3c09bf --- /dev/null +++ b/src/geo/include/RAT/HemisphereEncapsulation.hh @@ -0,0 +1,106 @@ +// This is the encapsulation model that is used for BUTTON. +// The 96 Hamamatsu r7081pe PMTs are encapsulated by two acryilic domes that are held together with metal flanges. +// Created by Lewis Sexton (Sheffield) and Adam Tarrant (Liverpool) + +#ifndef __RAT_HemisphereEncapsulation__ +#define __RAT_HemisphereEncapsulation__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace RAT { + +struct HemisphereEncapsulationParams { + int useMetalFlange; + int useGel; + int useSilicaBag; + int useCable; + + // encapsulation object dimensions + double envelope_radius; + double encap_radius; + double encap_thickness; + double flange_rmax; + double dome_flange_thickness; + double metal_flange_thickness; + double optical_gel_sub_height; + std::vector metal_flange_dimensions; + std::vector silica_bag_dimensions; + std::vector silica_bag_position; + std::vector cable_dimensions; + std::vector cable_position; + + // PMT Body + std::vector zEdge; // n+1 + std::vector rhoEdge; // n+1 + std::vector zOrigin; // n + G4ThreeVector pmtposvec; + std::vector posvec; + + G4Material *exterior_material; + G4Material *inner_encapsulation_material; + G4Material *front_encapsulation_material; + G4Material *rear_encapsulation_material; + G4Material *metal_flange_material; + G4Material *silica_bag_material; + G4Material *cable_material; + G4Material *optical_gel_material; + + G4OpticalSurface *inner_encapsulation_surface; + G4OpticalSurface *front_encapsulation_surface; + G4OpticalSurface *rear_encapsulation_surface; + G4OpticalSurface *metal_flange_surface; + G4OpticalSurface *cable_surface; + G4OpticalSurface *silica_bag_surface; + G4OpticalSurface *optical_gel_surface; +}; + +class HemisphereEncapsulation : public PMTEncapsulation { + public: + HemisphereEncapsulation(DBLinkPtr encaptable, DBLinkPtr pmttable, G4LogicalVolume *mother); + virtual ~HemisphereEncapsulation() {} + + virtual G4LogicalVolume *BuildVolume(const std::string &prefix); + virtual G4VSolid *BuildSolid(const std::string &prefix); + virtual G4PVPlacement *PlaceEncap(G4RotationMatrix *pmtrot, G4ThreeVector pmtpos, const std::string &name, + G4LogicalVolume *logi_pmt, G4VPhysicalVolume *mother_phys, bool booleanSolid, + int copyNo); + + protected: + G4VSolid *NewEnvelopeSolid(const std::string &name); + G4VSolid *NewEncapsulationSolid(const std::string &name); + G4VSolid *optical_gel_height_subtraction(const std::string &_name); + G4VSolid *optical_gel_pmt_subtraction(const std::string &_name, GLG4TorusStack *body); + + // phyiscal volumes + G4PVPlacement *inner_encapsulation_phys; + G4PVPlacement *optical_gel_encapsulation_phys; + G4PVPlacement *front_encapsulation_phys; + G4PVPlacement *rear_encapsulation_phys; + G4PVPlacement *front_metal_encapsulaion_flange_phys; + G4PVPlacement *rear_metal_encapsulation_flange_phys; + G4PVPlacement *silica_bag_encapsulation_phys; + G4PVPlacement *cable_encapsulation_phys; + + HemisphereEncapsulationParams fParams; +}; + +} // namespace RAT + +#endif diff --git a/src/geo/include/RAT/PMTEncapsulation.hh b/src/geo/include/RAT/PMTEncapsulation.hh new file mode 100644 index 00000000..340eef3c --- /dev/null +++ b/src/geo/include/RAT/PMTEncapsulation.hh @@ -0,0 +1,35 @@ +#ifndef __RAT_PMTEncapsulation__ +#define __RAT_PMTEncapsulation__ + +#include +#include +#include +#include +#include +#include + +namespace RAT { + +class PMTEncapsulation { + public: + static PMTEncapsulation *NewConstruction(DBLinkPtr encaptable, DBLinkPtr pmttable, G4LogicalVolume *mother); + + PMTEncapsulation(std::string _name) : name(_name) {} + + virtual ~PMTEncapsulation() {} + + virtual G4VSolid *BuildSolid(const std::string &prefix) = 0; + + virtual G4LogicalVolume *BuildVolume(const std::string &prefix) = 0; + + virtual G4PVPlacement *PlaceEncap(G4RotationMatrix *pmtrot, G4ThreeVector pmtpos, const std::string &name, + G4LogicalVolume *logi_pmt, G4VPhysicalVolume *mother_phys, bool booleanSolid, + int copyNo) = 0; + + protected: + std::string name; +}; + +} // namespace RAT + +#endif diff --git a/src/geo/src/pmt/HemisphereEncapsulation.cc b/src/geo/src/pmt/HemisphereEncapsulation.cc new file mode 100644 index 00000000..d6c109e4 --- /dev/null +++ b/src/geo/src/pmt/HemisphereEncapsulation.cc @@ -0,0 +1,490 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace RAT { + +HemisphereEncapsulation::HemisphereEncapsulation(DBLinkPtr encaptable, DBLinkPtr pmttable, G4LogicalVolume *mother) + : PMTEncapsulation("hemisphere") { + inner_encapsulation_phys = nullptr; + front_encapsulation_phys = nullptr; + rear_encapsulation_phys = nullptr; + + fParams.envelope_radius = 0; // default to 0 + try { + fParams.envelope_radius = encaptable->GetD("envelope_radius"); + } catch (DBNotFoundError &e) { + }; + if (fParams.envelope_radius == 0) { + Log::Die("Hemisphere encapsulation turned on but envelope radius not given!"); + } + + fParams.encap_radius = 0; // default to 0 + try { + fParams.encap_radius = encaptable->GetD("encap_radius"); + } catch (DBNotFoundError &e) { + }; + if (fParams.encap_radius == 0) { + Log::Die("Hemisphere encapsulation turned on but dome radius not given!"); + } + + fParams.encap_thickness = 0; // default to 0 + try { + fParams.encap_thickness = encaptable->GetD("encap_thickness"); + } catch (DBNotFoundError &e) { + }; + if (fParams.encap_thickness == 0) { + Log::Die("Hemisphere encapsulation turned on but dome thickness not given!"); + } + + fParams.flange_rmax = 0; // default to 0 + try { + fParams.flange_rmax = encaptable->GetD("flange_rmax"); + } catch (DBNotFoundError &e) { + }; + if (fParams.flange_rmax == 0) { + Log::Die("Hemisphere encapsulation turned on but flange max radius not given!"); + } + + fParams.useMetalFlange = 0; // default to no silica bag + try { + fParams.useMetalFlange = encaptable->GetI("use_metal_flange"); + } catch (DBNotFoundError &e) { + }; + if (fParams.useMetalFlange == 1) { + front_metal_encapsulaion_flange_phys = nullptr; + rear_metal_encapsulation_flange_phys = nullptr; + fParams.metal_flange_material = G4Material::GetMaterial(encaptable->GetS("metal_flange_material")); + fParams.metal_flange_surface = Materials::optical_surface[encaptable->GetS("metal_flange_material")]; + fParams.metal_flange_dimensions = encaptable->GetDArray("metal_flange_dimensions"); + } + + // PMT is only needed if optical gel is used + fParams.useGel = 0; // default to no gel + std::string pmttype = pmttable->GetS("construction"); + + // Check if optical gel can be used, needs toroidal + if (pmttype == "toroidal") { + info << "Optical gel can be used since PMT construction is toroidal" << newline; + try { + fParams.useGel = encaptable->GetI("use_optical_gel"); + } catch (DBNotFoundError &e) { + }; + } else if (pmttype != "toroidal") { + info << "Optical gel currently requires a toroidal PMT model, setting useGel = 0" << newline; + fParams.useGel = 0; + } + + if (fParams.useGel == 1) { + optical_gel_encapsulation_phys = nullptr; + + // Setup PMT parameters + fParams.zEdge = pmttable->GetDArray("z_edge"); + fParams.rhoEdge = pmttable->GetDArray("rho_edge"); + fParams.zOrigin = pmttable->GetDArray("z_origin"); + // Build PMT shape + assert(fParams.zEdge.size() == fParams.rhoEdge.size()); + assert(fParams.zEdge.size() == fParams.zOrigin.size() + 1); + + assert(fParams.exterior_material); + fParams.optical_gel_material = G4Material::GetMaterial(encaptable->GetS("optical_gel_material")); + fParams.optical_gel_surface = Materials::optical_surface[encaptable->GetS("optical_gel_material")]; + + fParams.optical_gel_sub_height = 0; // default to 0 + try { + fParams.optical_gel_sub_height = encaptable->GetD("optical_gel_sub_height"); + } catch (DBNotFoundError &e) { + }; + if (fParams.optical_gel_sub_height == 0) { + info << "No optical gel subtraction value given, set to 0" << newline; + } + + fParams.pmtposvec.setX(0.0); + fParams.pmtposvec.setY(0.0); + fParams.pmtposvec.setZ(0.0); + try { + fParams.posvec = encaptable->GetDArray("pmtposoffset"); + fParams.pmtposvec.setX(fParams.posvec[0] * CLHEP::mm); + fParams.pmtposvec.setY(fParams.posvec[1] * CLHEP::mm); + fParams.pmtposvec.setZ(fParams.posvec[2] * CLHEP::mm); + } catch (DBNotFoundError &e) { + }; + } + + fParams.useSilicaBag = 0; // default to no silica bag + try { + fParams.useSilicaBag = encaptable->GetI("use_silica_bag"); + } catch (DBNotFoundError &e) { + }; + if (fParams.useSilicaBag == 1) { + silica_bag_encapsulation_phys = nullptr; + fParams.silica_bag_material = G4Material::GetMaterial(encaptable->GetS("silica_bag_material")); + fParams.silica_bag_surface = Materials::optical_surface[encaptable->GetS("silica_bag_material")]; + fParams.silica_bag_dimensions = encaptable->GetDArray("silica_bag_dimensions"); + fParams.silica_bag_position = encaptable->GetDArray("silica_bag_position"); + } + + fParams.useCable = 0; // default to no cable + try { + fParams.useCable = encaptable->GetI("use_cable"); + } catch (DBNotFoundError &e) { + }; + if (fParams.useCable == 1) { + cable_encapsulation_phys = nullptr; + fParams.cable_material = G4Material::GetMaterial(encaptable->GetS("cable_material")); + fParams.cable_surface = Materials::optical_surface[encaptable->GetS("cable_material")]; + fParams.cable_dimensions = encaptable->GetDArray("cable_dimensions"); + fParams.cable_position = encaptable->GetDArray("cable_position"); + } + + // Encapsulation materials + fParams.exterior_material = mother->GetMaterial(); + fParams.inner_encapsulation_material = G4Material::GetMaterial(encaptable->GetS("inside_encapsulation_material")); + fParams.front_encapsulation_material = G4Material::GetMaterial(encaptable->GetS("front_encapsulation_material")); + fParams.rear_encapsulation_material = G4Material::GetMaterial(encaptable->GetS("rear_encapsulation_material")); + + // Encapsulation surface + fParams.inner_encapsulation_surface = Materials::optical_surface[encaptable->GetS("inside_encapsulation_material")]; + fParams.front_encapsulation_surface = Materials::optical_surface[encaptable->GetS("front_encapsulation_material")]; + fParams.rear_encapsulation_surface = Materials::optical_surface[encaptable->GetS("rear_encapsulation_material")]; +} + +G4LogicalVolume *HemisphereEncapsulation::BuildVolume(const std::string &prefix) { + // ---------- Generate Shapes ---------- + + // Generate Envelope which will house encapsulation and PMT + G4VSolid *envelope_solid = NewEnvelopeSolid("envelope_solid"); + + G4VSolid *front_encapsulation_solid = + new G4Sphere("front_encapsulation_solid", + (fParams.encap_radius) * CLHEP::mm, // rmin + (fParams.encap_radius + fParams.encap_thickness) * CLHEP::mm, // rmax + 0.5 * CLHEP::pi, CLHEP::twopi, // phi + 0.0, 0.5 * CLHEP::pi); // theta + + G4VSolid *rear_encapsulation_solid = + new G4Sphere("rear_encapsulation_solid", + (fParams.encap_radius) * CLHEP::mm, // rmin + (fParams.encap_radius + fParams.encap_thickness) * CLHEP::mm, // rmax + 0.5 * CLHEP::pi, CLHEP::twopi, // phi + 0.5 * CLHEP::pi, 0.5 * CLHEP::pi); // theta + + G4VSolid *dome_flange_solid = + new G4Tubs("dome_flange_solid", + (fParams.encap_radius) * CLHEP::mm, // rmin + (fParams.flange_rmax) * CLHEP::mm, // rmax + (0.5 * fParams.encap_thickness) * CLHEP::mm, // zhalf, thickness is same as dome thickness so 0.8/2.0 + 0.0, CLHEP::twopi); // phi + + front_encapsulation_solid = + new G4UnionSolid("front_encapsulation_solid", front_encapsulation_solid, dome_flange_solid, 0, + G4ThreeVector(0.0, 0.0, (0.5 * fParams.encap_thickness) * CLHEP::mm)); + + rear_encapsulation_solid = new G4UnionSolid("rear_encapsulation_solid", rear_encapsulation_solid, dome_flange_solid, + 0, G4ThreeVector(0.0, 0.0, -(0.5 * fParams.encap_thickness) * CLHEP::mm)); + + G4Tubs *metal_flange_solid = nullptr; + if (fParams.useMetalFlange == 1) { + metal_flange_solid = new G4Tubs("front_metal_flange_solid", + (fParams.metal_flange_dimensions[0]) * CLHEP::mm, // rmin + (fParams.metal_flange_dimensions[1]) * CLHEP::mm, // rmax + (fParams.metal_flange_dimensions[2]) * CLHEP::mm, // size z half + 0.0, CLHEP::twopi); // phi + } + + G4Sphere *inner_encapsulation_solid = new G4Sphere("inner_encapsulation_solid", + 0.0 * CLHEP::mm, // rmin + (fParams.encap_radius) * CLHEP::mm, // rmax + 0.0, CLHEP::twopi, // phi + 0.0, CLHEP::twopi); // theta + + // If optical gel is used generate pmt shape to substract from gel + // NOTE: THIS WILL ONLY WORK FOR TOROIDAL + G4VSolid *optical_gel_encapsulation_solid = nullptr; + GLG4TorusStack *body_solid = nullptr; + + if (fParams.useGel == 1) { + body_solid = (GLG4TorusStack *)BuildSolid(prefix + "_body_solid"); + if (body_solid != NULL) { + info << "pmt shape made" << newline; + } + optical_gel_encapsulation_solid = + optical_gel_pmt_subtraction(prefix + "_optical_gel_encapsulation_solid", body_solid); + } + + G4Box *silica_bag_solid = nullptr; + if (fParams.useSilicaBag == 1) { + silica_bag_solid = + new G4Box("silica_bag_solid", (fParams.silica_bag_dimensions[0]) * CLHEP::mm, + (fParams.silica_bag_dimensions[1]) * CLHEP::mm, (fParams.silica_bag_dimensions[2]) * CLHEP::mm); + } + + G4Tubs *cable_solid = nullptr; + if (fParams.useCable == 1) { + cable_solid = new G4Tubs("cable_solid", + (fParams.cable_dimensions[0]) * CLHEP::mm, // rmin + (fParams.cable_dimensions[1]) * CLHEP::mm, // rmax + (fParams.cable_dimensions[2]) * CLHEP::mm, // size z + 0.0, CLHEP::twopi); // phi + } + + // ---------- Logical volumes ---------- + + G4LogicalVolume *envelope_log, *front_encapsulation_log, *rear_encapsulation_log, + *metal_flange_encapsulation_log = nullptr; + G4LogicalVolume *inner_encapsulation_log, *optical_gel_encapsulation_log = nullptr, + *silica_bag_encapsulation_log = nullptr, *cable_encapsulation_log = nullptr; + + envelope_log = new G4LogicalVolume(envelope_solid, fParams.exterior_material, "envelope_log"); + + front_encapsulation_log = + new G4LogicalVolume(front_encapsulation_solid, fParams.front_encapsulation_material, "front_encapsulation_log"); + + rear_encapsulation_log = + new G4LogicalVolume(rear_encapsulation_solid, fParams.rear_encapsulation_material, "rear_encapsulation_log"); + + if (fParams.useMetalFlange == 1) { + metal_flange_encapsulation_log = + new G4LogicalVolume(metal_flange_solid, fParams.metal_flange_material, "metal_flange_encapsulation_log"); + } + + inner_encapsulation_log = + new G4LogicalVolume(inner_encapsulation_solid, fParams.inner_encapsulation_material, "inner_encapsulation_log"); + + if (fParams.useGel == 1) { + optical_gel_encapsulation_log = new G4LogicalVolume(optical_gel_encapsulation_solid, fParams.optical_gel_material, + "optical_gel_encapsulation_log"); + } + + if (fParams.useSilicaBag == 1) { + silica_bag_encapsulation_log = + new G4LogicalVolume(silica_bag_solid, fParams.silica_bag_material, "silica_bag_encapsulation_log"); + } + + if (fParams.useCable == 1) { + cable_encapsulation_log = new G4LogicalVolume(cable_solid, fParams.cable_material, "cable_encapsulation_log"); + } + + // ---------- Physical volumes ---------- + + front_encapsulation_phys = + new G4PVPlacement(0, // rotation + G4ThreeVector(0.0, 0.0, 0.0), // position + front_encapsulation_log, // the logical volume + prefix + "_front_dome_encapsulation_phys", // a name for this physical volume + envelope_log, // the mother volume + false, // no boolean ops + 0); // copy number + + rear_encapsulation_phys = + new G4PVPlacement(0, // rotation + G4ThreeVector(0.0, 0.0, 0.0), // position + rear_encapsulation_log, // the logical volume + prefix + "_rear_dome_encapsulation_phys", // a name for this physical volume + envelope_log, // the mother volume + false, // no boolean ops + 0); // copy number + + if (fParams.useMetalFlange == 1) { + double metal_flange_zpos = (fParams.encap_thickness + fParams.metal_flange_dimensions[2]) * CLHEP::mm; + front_metal_encapsulaion_flange_phys = + new G4PVPlacement(0, // rotation + G4ThreeVector(0.0, 0.0, metal_flange_zpos), // position + metal_flange_encapsulation_log, // the logical volume + prefix + "_front_metal_flange_encapsulation_phys", // a name for this physical volume + envelope_log, // the mother volume + false, // no boolean ops + 0); // copy number + + rear_metal_encapsulation_flange_phys = + new G4PVPlacement(0, // rotation + G4ThreeVector(0.0, 0.0, -metal_flange_zpos), // position + metal_flange_encapsulation_log, // the logical volume + prefix + "rear_metal_flange_encapsulation_phys", // a name for this physical volume + envelope_log, // the mother volume + false, // no boolean ops + 0); // copy number + } + + inner_encapsulation_phys = + new G4PVPlacement(0, // rotation + G4ThreeVector(0.0, 0.0, 0.0), // position + inner_encapsulation_log, // the logical volume + prefix + "_inner_volume_encapsulation_phys", // a name for this physical volume + envelope_log, // the mother volume + false, // no boolean ops + 0); + + if (fParams.useGel == 1) { + optical_gel_encapsulation_phys = + new G4PVPlacement(0, // rotation + G4ThreeVector(0.0, 0.0, 0.0), // position + optical_gel_encapsulation_log, // the logical volume + prefix + "_gel_encapsulation_phys", // a name for this physical volume + inner_encapsulation_log, // the mother volume + false, // no boolean ops + 0); + } + + if (fParams.useSilicaBag == 1) { + G4ThreeVector silicaposition(fParams.silica_bag_position[0] * CLHEP::mm, fParams.silica_bag_position[1] * CLHEP::mm, + fParams.silica_bag_position[2] * CLHEP::mm); + + silica_bag_encapsulation_phys = + new G4PVPlacement(0, // rotation + silicaposition, // position + silica_bag_encapsulation_log, // the logical volume + prefix + "_silica_encapsulation_phys", // a name for this physical volume + inner_encapsulation_log, // the mother volume + false, // no boolean ops + 0); + } + + if (fParams.useCable == 1) { + G4ThreeVector cableposition(fParams.cable_position[0] * CLHEP::mm, fParams.cable_position[1] * CLHEP::mm, + fParams.cable_position[2] * CLHEP::mm); + + cable_encapsulation_phys = + new G4PVPlacement(0, // rotation + cableposition, // position + cable_encapsulation_log, // the logical volume + prefix + "_cable_encapsulation_phys", // a name for this physical volume + inner_encapsulation_log, // the mother volume + false, // no boolean ops + 0); + } + + // ---------- Skin surfaces ---------- + new G4LogicalSkinSurface("front_encapsulation_skin", + front_encapsulation_log, // Logical Volume + fParams.front_encapsulation_surface); // Surface Property + + new G4LogicalSkinSurface("rear_encapsulation_skin", + rear_encapsulation_log, // Logical Volume + fParams.rear_encapsulation_surface); // Surface Property + + if (fParams.useMetalFlange == 1) { + new G4LogicalSkinSurface("metal_flange_encapsulation_skin", + metal_flange_encapsulation_log, // Logical Volume + fParams.metal_flange_surface); // Surface Property + } + + new G4LogicalSkinSurface("inner_encapsulation_skin", + inner_encapsulation_log, // Logical Volume + fParams.inner_encapsulation_surface); // Surface Property + + if (fParams.useGel == 1) { + new G4LogicalSkinSurface("optical_gel_encapsulation_skin", + optical_gel_encapsulation_log, // Logical Volume + fParams.optical_gel_surface); // Surface Property + } + + if (fParams.useSilicaBag == 1) { + new G4LogicalSkinSurface("silica_bag_encapsulation_skin", + silica_bag_encapsulation_log, // Logical Volume + fParams.silica_bag_surface); // Surface Property + } + + if (fParams.useCable == 1) { + new G4LogicalSkinSurface("cable_encapsulation_skin", + cable_encapsulation_log, // Logical Volume + fParams.cable_surface); // Surface Property + } + + // ---------- Border Surface ---------- + + new G4LogicalBorderSurface(prefix + "_backencap_logsurf1", rear_encapsulation_phys, inner_encapsulation_phys, + fParams.rear_encapsulation_surface); + new G4LogicalBorderSurface(prefix + "_backencap_logsurf2", inner_encapsulation_phys, rear_encapsulation_phys, + fParams.rear_encapsulation_surface); + + // ---------- Visual Attributes ---------- + G4VisAttributes *visAtt; + + envelope_log->SetVisAttributes(G4VisAttributes::GetInvisible()); + + visAtt = new G4VisAttributes(G4Color(0.44, 0.52, 0.78, 0.5)); + front_encapsulation_log->SetVisAttributes(visAtt); + + visAtt = new G4VisAttributes(G4Color(0., 0.03, 0.14, 1.)); + rear_encapsulation_log->SetVisAttributes(visAtt); + + if (fParams.useMetalFlange == 1) { + visAtt = new G4VisAttributes(G4Color(0.68, 0.68, 0.68, 1.0)); + metal_flange_encapsulation_log->SetVisAttributes(visAtt); + } + + visAtt = new G4VisAttributes(G4Color(0.77, 0.97, 1., 0.3)); + inner_encapsulation_log->SetVisAttributes(visAtt); + + if (fParams.useGel == 1) { + visAtt = new G4VisAttributes(G4Color(0.87, 0.81, 0.11, 0.5)); + optical_gel_encapsulation_log->SetVisAttributes(visAtt); + } + + if (fParams.useSilicaBag == 1) { + visAtt = new G4VisAttributes(G4Color(0.3, 0.1, 0.1, 1.0)); + silica_bag_encapsulation_log->SetVisAttributes(visAtt); + } + if (fParams.useCable == 1) { + visAtt = new G4VisAttributes(G4Color(1.0, 0.18, 0.8, 1.0)); + cable_encapsulation_log->SetVisAttributes(visAtt); + } + + return envelope_log; +} + +G4VSolid *HemisphereEncapsulation::BuildSolid(const std::string &_name) { + GLG4TorusStack *body = new GLG4TorusStack(_name); + body->SetAllParameters(fParams.zOrigin.size(), &fParams.zEdge[0], &fParams.rhoEdge[0], &fParams.zOrigin[0]); + return body; +} + +G4VSolid *HemisphereEncapsulation::optical_gel_height_subtraction(const std::string &_name) { + G4Sphere *optical_gel_1 = + new G4Sphere("optical_gel_1_encapsulation_solid", 0.0 * CLHEP::mm, (fParams.encap_radius) * CLHEP::mm, + 0.5 * CLHEP::pi, CLHEP::twopi, 0.0, 0.5 * CLHEP::pi); + + G4Tubs *gel_subtract = new G4Tubs("gel_sub_solid", 0.0, + (fParams.encap_radius) * CLHEP::mm, // solid cylinder + (fParams.optical_gel_sub_height) * CLHEP::mm, // half height of cylinder + 0.0, CLHEP::twopi); // cylinder complete in phi + + return new G4SubtractionSolid(_name, optical_gel_1, gel_subtract, 0, G4ThreeVector(0.0, 0.0, 0.0)); +} + +G4VSolid *HemisphereEncapsulation::optical_gel_pmt_subtraction(const std::string &_name, GLG4TorusStack *body) { + G4VSolid *optical_gel_2 = optical_gel_height_subtraction("temp_gel" + _name); + + return new G4SubtractionSolid(_name, optical_gel_2, body, 0, fParams.pmtposvec); +} + +G4PVPlacement *HemisphereEncapsulation::PlaceEncap(G4RotationMatrix *pmtrot, G4ThreeVector pmtpos, + const std::string &_name, G4LogicalVolume *logi_pmt, + G4VPhysicalVolume *mother_phys, bool booleanSolid, int copyNo) { + return new G4PVPlacement(pmtrot, pmtpos, _name, logi_pmt, mother_phys, booleanSolid, copyNo); +} + +G4VSolid *HemisphereEncapsulation::NewEnvelopeSolid(const std::string &_name) { + G4Sphere *outer_s = new G4Sphere(_name + "_main", 0. * CLHEP::mm, fParams.envelope_radius * CLHEP::mm, 0.0, + CLHEP::twopi, 0.0, CLHEP::twopi); + return outer_s; +} + +} // namespace RAT diff --git a/src/geo/src/pmt/PMTEncapsulation.cc b/src/geo/src/pmt/PMTEncapsulation.cc new file mode 100644 index 00000000..f350d1e0 --- /dev/null +++ b/src/geo/src/pmt/PMTEncapsulation.cc @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace RAT { + +PMTEncapsulation *PMTEncapsulation::NewConstruction(DBLinkPtr encaptable, DBLinkPtr pmttable, G4LogicalVolume *mother) { + std::string construction = encaptable->Get("construction"); + if (construction == "hemisphere") { + return new HemisphereEncapsulation(encaptable, pmttable, mother); + } else { + Log::Die("PMT encapsulation \'" + construction + "\' does not exist."); + } + return NULL; +} + +} // namespace RAT diff --git a/src/geo/src/pmt/PMTFactoryBase.cc b/src/geo/src/pmt/PMTFactoryBase.cc index 651f6e07..05ac9b02 100644 --- a/src/geo/src/pmt/PMTFactoryBase.cc +++ b/src/geo/src/pmt/PMTFactoryBase.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -45,8 +46,54 @@ G4VPhysicalVolume *PMTFactoryBase::ConstructPMTs( } G4ThreeVector local_offset = PMTInfoParser::ComputeLocalOffset(mother_name); - PMTConstruction *construction = PMTConstruction::NewConstruction(lpmt, mother); - G4LogicalVolume *log_pmt = construction->BuildVolume(volume_name); + PMTEncapsulation *encap_construction = nullptr; + G4LogicalVolume *log_encapenv = nullptr; + PMTConstruction *construction = nullptr; + G4LogicalVolume *log_pmt = nullptr; + G4VPhysicalVolume *phys_mother_encap = nullptr; + G4ThreeVector pmtoffsetposition(0.0, 0.0, 0.0); + + int encapsulation = 0; // default to no encapsulation + try { + encapsulation = table->GetI("encapsulation"); + } catch (DBNotFoundError &e) { + }; + if (encapsulation == 1) { + std::string encapsulation_model = table->GetS("encapsulation_model"); // get encapsulation model e.g. BUTTON + DBLinkPtr lencapsulation = DB::Get()->GetLink( + "ENCAPSULATION", encapsulation_model); // find model in ENCAPSULATION.RATDB, need to make this file + + info << "Encapsulation is turned on, using model: " << encapsulation_model << newline; + + encap_construction = PMTEncapsulation::NewConstruction(lencapsulation, lpmt, + mother); // make encapsulation, need to make/modify file + log_encapenv = encap_construction->BuildVolume(volume_name); + + try { + std::vector posvector = lencapsulation->GetDArray("pmtposoffset"); + pmtoffsetposition.setX(posvector[0] * CLHEP::mm); + pmtoffsetposition.setY(posvector[1] * CLHEP::mm); + pmtoffsetposition.setZ(posvector[2] * CLHEP::mm); + } catch (DBNotFoundError &e) { + }; + + mother = + FindMother("inner_encapsulation_log"); // change mother so that pmt is placed inside encapsulation volume now + if (mother == 0) { + Log::Die("PMTParser: Unable to find mother volume " + mother_name + " for " + volume_name); + } + phys_mother_encap = FindPhysMother(volume_name + "_inner_volume_encapsulation_phys"); + if (phys_mother == 0) { + Log::Die("PMTParser: PMT mother physical volume " + mother_name + " not found"); + } + } + + construction = PMTConstruction::NewConstruction(lpmt, mother); + log_pmt = construction->BuildVolume(volume_name); + + if (encapsulation == 1) { + construction->PlacePMT(0, pmtoffsetposition, volume_name + "_body_phys", log_pmt, phys_mother_encap, false, 0); + } /* BFields not in the database anywhere and should be looked at */ // FIXME take a look at what's going on with the Bfield stuff - no docs on @@ -240,6 +287,16 @@ G4VPhysicalVolume *PMTFactoryBase::ConstructPMTs( // TODO: We should also account for a rotation of the mother volume at some point G4ThreeVector pmtpos_global = pmtpos + local_offset; + // PMT may have been placed offset from encapsulation origin, assume pmt only moved forward/backwards (z position + // change) + if (encapsulation == 1) { + G4ThreeVector extra_offset; + extra_offset.setX(pmtdir.x() * pmtoffsetposition.z()); + extra_offset.setY(pmtdir.y() * pmtoffsetposition.z()); + extra_offset.setZ(pmtdir.z() * pmtoffsetposition.z()); + pmtpos_global += extra_offset; + } + // Store individual efficiency EfficiencyCorrection[id] = pmt_effi_corr[i]; @@ -355,16 +412,20 @@ G4VPhysicalVolume *PMTFactoryBase::ConstructPMTs( pmtrot->rotateY(angle_y); pmtrot->rotateX(angle_x); - construction->PlacePMT(pmtrot, pmtpos, pmtname, log_pmt, phys_mother, false, id); - + if (encapsulation == 1) { + encap_construction->PlaceEncap(pmtrot, pmtpos, pmtname, log_encapenv, phys_mother, false, id); + } else { + construction->PlacePMT(pmtrot, pmtpos, pmtname, log_pmt, phys_mother, false, id); + } } // end loop over id // finally pass the efficiency table to GLG4PMTOpticalModel const G4String modname(volume_name + "_optical_model"); // In case the main pmt volume doesn't correspond to the fastsim region + G4LogicalVolume *fastsim_log_pmt = log_pmt; if (fastsim_log_pmt->GetFastSimulationManager() == NULL) { - fastsim_log_pmt = log_pmt->GetDaughter(0)->GetLogicalVolume(); // Get the glass region + fastsim_log_pmt = log_pmt->GetDaughter(0)->GetLogicalVolume(); } for (size_t i = 0; i < fastsim_log_pmt->GetFastSimulationManager()->GetFastSimulationModelList().size(); i++) {