#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace CLHEP; namespace RAT { GeoPMTBuilderBase::GeoPMTBuilderBase() { } GeoPMTBuilderBase::~GeoPMTBuilderBase() { for( map::iterator iTer = fPMT.begin(); iTer != fPMT.end(); ++iTer ) delete iTer->second; fPMT.clear(); for( map::iterator iTer = fConcentrator.begin(); iTer != fConcentrator.end(); ++iTer ) delete iTer->second; fConcentrator.clear(); for( map::iterator iTer = fBucket.begin(); iTer != fBucket.end(); ++iTer ) delete iTer->second; fBucket.clear(); for( map::iterator iTer = fPMTBase.begin(); iTer != fPMTBase.end(); ++iTer ) delete iTer->second; fPMTBase.clear(); for( map::iterator iTer = fEnvelope.begin(); iTer != fEnvelope.end(); ++iTer ) delete iTer->second; fEnvelope.clear(); } void GeoPMTBuilderBase::AssembleFullPMT( const int pmtBuildType, G4VisAttributes* visAttributes ) { // Firstly calculate the required size of the envelope // Note: All coords are relative to PMT equator until placement in Mother volume // Get the top, bottom and radius coords for the envelope, note this is done such that PMT equator is at z=0 in the envelope double envelopeTop = fPMT[pmtBuildType]->GetMaxHeight(); //Max double envelopeBottom = fPMT[pmtBuildType]->GetMaxDepth(); //Min to compare as minus number (as below equator) double envelopeRadius = fPMT[pmtBuildType]->GetHexRadius(); //Max int numFaces = 0; // Number of faces on the envelope if( fPMT.count( pmtBuildType ) == 0 ) Log::Die( "GeoPMTBuilderBase::AssembleFullPMT attempted with no previously constructed PMT." ); if( fConcentrator.count( pmtBuildType ) != 0 ) { envelopeTop = std::max( envelopeTop, fConcentrator[pmtBuildType]->GetMaxHeight() ); envelopeBottom = std::min( envelopeBottom, fConcentrator[pmtBuildType]->GetMaxDepth() ); envelopeRadius = std::max( envelopeRadius, fConcentrator[pmtBuildType]->GetHexRadius() ); } if( fBucket.count( pmtBuildType ) != 0 ) { numFaces = 6; envelopeTop = std::max( envelopeTop, fBucket[pmtBuildType]->GetMaxHeight() ); envelopeBottom = std::min( envelopeBottom, fBucket[pmtBuildType]->GetMaxDepth() ); envelopeRadius = std::max( envelopeRadius, fBucket[pmtBuildType]->GetHexRadius() ); } if( fPMTBase.count( pmtBuildType ) != 0 ) { envelopeTop = std::max( envelopeTop, fPMTBase[pmtBuildType]->GetMaxHeight() ); envelopeBottom = std::min( envelopeBottom, fPMTBase[pmtBuildType]->GetMaxDepth() ); envelopeRadius = std::max( envelopeRadius, fPMTBase[pmtBuildType]->GetHexRadius() ); } // increase the front surface for safety envelopeTop += 1.0; if( fPMT[pmtBuildType]->GetShape() == PMTConstructorParams::eCuboid ) { CuboidPMTConstructor* pmt = dynamic_cast( fPMT[pmtBuildType] ); fEnvelope[pmtBuildType] = new EnvelopeConstructor( fPrefix, envelopeTop, envelopeBottom, pmt->GetXWidth(), pmt->GetYWidth(), visAttributes, fMotherMaterial ); } else fEnvelope[pmtBuildType] = new EnvelopeConstructor( fPrefix, envelopeTop, envelopeBottom, envelopeRadius, numFaces, visAttributes, fMotherMaterial ); fEnvelope[pmtBuildType]->SetLogicalVolume( fPMT[pmtBuildType]->GetLogicalVolume() ); fEnvelope[pmtBuildType]->Construct(); const double envelopeOffset = fEnvelope[pmtBuildType]->GetOffset(); // First Place PMT body in envelope G4PVPlacement* bodyPhys = new G4PVPlacement( 0, // no rotation G4ThreeVector( 0.0, 0.0, -envelopeOffset ), fPMT[pmtBuildType]->GetLogicalVolume(), // The PMT Body logical volume fPrefix + "_pmt", // a name for this physical volume fEnvelope[pmtBuildType]->GetLogicalVolume(), // the Envelope Logical volume false, // no boolean ops 0 ); // copy number // Finish constructing PMTs now the bodyPhys exists fPMT[pmtBuildType]->ConstructPhysical( bodyPhys ); // Now add the extra parts to the envelope if( fConcentrator.count( pmtBuildType ) != 0 ) { const G4ThreeVector concOffset = G4ThreeVector( 0, 0, fConcentrator[pmtBuildType]->GetOffset() - envelopeOffset ); new G4PVPlacement( 0, // no rotation concOffset, // translate fConcentrator[pmtBuildType]->GetLogicalVolume(), // the logical volume fPrefix + "_concentrator", // a name for this physical volume fEnvelope[pmtBuildType]->GetLogicalVolume(), // the mother volume false, // no boolean ops 0 ); } if( fBucket.count( pmtBuildType ) != 0 ) { const G4ThreeVector bucketOffset = G4ThreeVector( 0, 0, fBucket[pmtBuildType]->GetOffset() - envelopeOffset ); new G4PVPlacement( 0, // no rotation bucketOffset, // translate fBucket[pmtBuildType]->GetLogicalVolume(), // the logical volume fPrefix + "_bucket", // a name for this physical volume fEnvelope[pmtBuildType]->GetLogicalVolume(), // the mother volume false, // no boolean ops 0 ); } if( fPMTBase.count( pmtBuildType ) != 0 ) { const G4ThreeVector pmtBaseOffset = G4ThreeVector( 0, 0, fPMTBase[pmtBuildType]->GetOffset() - envelopeOffset ); new G4PVPlacement( 0, // no rotation pmtBaseOffset, // translate fPMTBase[pmtBuildType]->GetLogicalVolume(), // the logical volume fPrefix + "_pmtbase", // a name for this physical volume fEnvelope[pmtBuildType]->GetLogicalVolume(), // the mother volume false, // no boolean ops 0 ); } } void GeoPMTBuilderBase::SetupFullOpticalModel( const int pmtBuildType ) { if( fConcentrator[pmtBuildType] != NULL ) { G4Region* concOpticalModelRegion = new G4Region( fPrefix + "_ConcentratorOpticalRegion" ); concOpticalModelRegion->AddRootLogicalVolume( fConcentrator[pmtBuildType]->GetLogicalVolume() ); if( fConcentrator[pmtBuildType]->GetModelType() == "ConcOptics0" ) { new ConcentratorOpticalModel( fPrefix + "_conc_optical_model", concOpticalModelRegion, fConcentrator[pmtBuildType]->GetModelParams(), fConcentrator[pmtBuildType]->GetLogicalVolume() ); } else if( fConcentrator[pmtBuildType]->GetModelType() == "ConcOpticsSNOMAN" ) { new ConcentratorSNOMANOpticalModel( fPrefix + "_conc_optical_model", concOpticalModelRegion, fConcentrator[pmtBuildType]->GetModelParams(), fConcentrator[pmtBuildType]->GetLogicalVolume() ); } else if( fConcentrator[pmtBuildType]->GetModelType() == "ConcOpticsAged" ) { new ConcentratorAgedOpticalModel( fPrefix + "_conc_optical_model", concOpticalModelRegion, fConcentrator[pmtBuildType]->GetModelParams(), fConcentrator[pmtBuildType]->GetLogicalVolume() ); } else { Log::Die("GeoPMTBuilderBase::SetupOpticalModel: Unknown model type specified"); } } // Now the PMT optical Model G4Region* pmtOpticalModelRegion = new G4Region( fPrefix + "_PMTOpticalRegion" ); pmtOpticalModelRegion->AddRootLogicalVolume( fPMT[pmtBuildType]->GetLogicalVolume() ); if( fPMT[pmtBuildType]->GetModelType() == "PMTOptics0" ) { new PMTOpticalModel( fPrefix + "_pmt_optical_model", pmtOpticalModelRegion, fPMT[pmtBuildType]->GetModelParams(), fPMT[pmtBuildType]->GetLogicalVolume(), fEnvelope[pmtBuildType]->GetLogicalVolume(), fPMT[pmtBuildType]->GetPhotocathodeSurface(), fPMT[pmtBuildType]->GetMirrorSurface() ); } else if( fPMT[pmtBuildType]->GetModelType() == "PMTOpticsSNOMAN" ) { new PMTSNOMANOpticalModel( fPrefix + "_pmt_optical_model", pmtOpticalModelRegion, fPMT[pmtBuildType]->GetModelParams(), fPMT[pmtBuildType]->GetLogicalVolume(), fEnvelope[pmtBuildType]->GetLogicalVolume(), fPMT[pmtBuildType]->GetPhotocathodeSurface(), fPMT[pmtBuildType]->GetMirrorSurface() ); } else { Log::Die("GeoPMTBuilderBase::SetupOpticalModel: Unkown model type specified"); } } void GeoPMTBuilderBase::SetupDiscOpticalModel( const int pmtBuildType, const std::string& /*model*/, // Currently unused, only one disc model exists const std::string& params ) { if( fEnvelope[pmtBuildType] == NULL ) Log::Die( "GeoPMTBuilderBase::SetupOpticalModel: Disc model specified without envelope." ); G4Region* opticalModelRegion = new G4Region( fPrefix + "_DiscOpticalRegion" ); opticalModelRegion->AddRootLogicalVolume( fEnvelope[pmtBuildType]->GetLogicalVolume() ); // Place the disc at the envelope or bucket front face double discTop = fEnvelope[pmtBuildType]->GetMaxHeight(); if( fBucket.count( pmtBuildType ) != 0 ) discTop = fBucket[pmtBuildType]->GetMaxHeight(); new DiscOpticalModel( fPrefix + "_optical_model", opticalModelRegion, params, fEnvelope[pmtBuildType]->GetLogicalVolume(), discTop ); } void GeoPMTBuilderBase::ConstructPMT( const int pmtBuildType, const PMTConstructorParams& params ) { if( params.fShape == PMTConstructorParams::eTorus ) fPMT[pmtBuildType] = new TorusPMTConstructor( fPrefix, params ); // Deleted in this class' destructor else if( params.fShape == PMTConstructorParams::eCuboid ) fPMT[pmtBuildType] = new CuboidPMTConstructor( fPrefix, params ); // Deleted in this class' destructor else if( params.fShape == PMTConstructorParams::eCylindrical ) fPMT[pmtBuildType] = new CylindricalPMTConstructor( fPrefix, params ); // Deleted in this class' destructor else Log::Die( "GeoPMTBuilderBase::ConstructConc, bizarre concentrator definition" ); fPMT[pmtBuildType]->ConstructLogical(); } void GeoPMTBuilderBase::ConstructConc( const int pmtBuildType, const ConcentratorConstructorParams& params ) { if( params.fConcDefinition == ConcentratorConstructorParams::eSNOMAN ) fConcentrator[pmtBuildType] = new SNOMANConcentratorConstructor( fPrefix, params ); // Deleted in this class' destructor else if( params.fConcDefinition == ConcentratorConstructorParams::eRAT ) fConcentrator[pmtBuildType] = new RATConcentratorConstructor( fPrefix, params ); // Deleted in this class' destructor else Log::Die( "GeoPMTBuilderBase::ConstructConc, bizarre concentrator definition" ); fConcentrator[pmtBuildType]->Construct(); } void GeoPMTBuilderBase::ConstructBucket( const int pmtBuildType, const BucketConstructorParams& params ) { fBucket[pmtBuildType] = new BucketConstructor( fPrefix, params ); // Deleted in this class' destructor fBucket[pmtBuildType]->Construct(); } void GeoPMTBuilderBase::ConstructPMTBase( const int pmtBuildType, const PMTBaseConstructorParams& params ) { fPMTBase[pmtBuildType] = new PMTBaseConstructor( fPrefix, params ); // Deleted in this class' destructor fPMTBase[pmtBuildType]->Construct(); } void GeoPMTBuilderBase::CorrectPMTPosAndDir( const int pmtBuildType, G4ThreeVector& position, G4ThreeVector& direction ) const { //Firstly directions in the database point outwards, thus flip direction = -direction; direction = direction.unit(); // Secondly the position refers to the concentrator front face position not equator for normal pmts // Note, the Max height is the distance above the PMT equator in local coords. if( fBucket.count( pmtBuildType ) == 0 && (pmtBuildType == DU::PMTInfo::NORMAL || pmtBuildType == DU::PMTInfo::HQE) ) { warn << "GeoPMTBuilderBase::CorrectPMTPosAndDir Issue : No bucket included, PMTs will not be positioned correctly\n"; return; } if( pmtBuildType == DU::PMTInfo::NORMAL || pmtBuildType == DU::PMTInfo::HQE) position += -(direction * 131.6 *mm );//fBucket.find( pmtBuildType )->second->GetMaxHeight() ); // Now correct for envelope offset (if any) if( fEnvelope.count( pmtBuildType ) == 1 ) position += direction * fEnvelope.find( pmtBuildType )->second->GetOffset(); } } //::RAT