#include #include #include #include #include #include #include #include #include #include #include #include using namespace RAT; using namespace CLHEP; using namespace std; const double kOverlapGap = 1.5 * mm; const double PanelBase::fPMTRadius = 147.6 * mm; //Face gap?? const double PanelBase::fPMTb = fPMTRadius / cos( pi / 6.0 * rad ); const double PanelBase::fPMTc = fPMTRadius * tan( pi / 6.0 * rad ); const double PanelBase::fPMTd = fPMTb - fPMTb * cos ( pi / 3.0 * rad ); PanelBase::PanelBase( const std::string& prefix, const G4ThreeVector& position, const G4ThreeVector& zAxis, const G4ThreeVector& xAxis, G4Material* panelMaterial, G4VisAttributes* visAttributes ) { fPrefix = prefix; fPanelOrigin = position; assert( zAxis.dot( xAxis ) < 1e-5 ); // Check the axis passed are orthogonal fPanelZaxis = zAxis.unit(); fPanelXaxis = xAxis.unit(); fPanelYaxis = fPanelZaxis.cross( fPanelXaxis ); fPanelYaxis = fPanelYaxis.unit(); fPanelHeight = 0.0; fPanelDepth = 0.0; fPanelMaterial = panelMaterial; fVisAttributes = visAttributes; fPanelLogical = NULL; fPMTs.clear(); } void PanelBase::Construct( const bool checkOverlaps ) { // First build the panel volume ConstructPanel(); // Remove the panel where PMTs are missing CutPMTs(); // Now cut the edge CutEdge(); // Now place the pmts in the panel PlacePMTs( checkOverlaps ); } void PanelBase::AddPMT( EnvelopeConstructor* pmtEnvelope, const int pmtID, const G4ThreeVector& globalPosition, const G4ThreeVector& globalDirection ) { // First check the direction matches that of the panel assert( globalDirection.dot( fPanelZaxis ) > 1.0 - 1e-5 ); // Now setup the panel height fPanelHeight = max( pmtEnvelope->GetMaxHeight(), fPanelHeight ); fPanelDepth = min( pmtEnvelope->GetMaxDepth(), fPanelDepth ); // Now locate this pmt in the known positions G4ThreeVector globalOffset = globalPosition - fPanelOrigin; G4ThreeVector localPosition = G4ThreeVector( fPanelXaxis.dot( globalOffset ), fPanelYaxis.dot( globalOffset ), fPanelZaxis.dot( globalOffset ) ); for( vector< PanelPMT >::iterator iTer = fPMTs.begin(); iTer != fPMTs.end(); ++iTer ) { if( ( iTer->fPos - localPosition ).mag() < 2.0 * mm ) // Within 2 mm? { iTer->fEnvelope = pmtEnvelope; iTer->fID = pmtID; return; } } // If get here then PMT is not in this panel, so error out Log::Die( "PanelBase::AddPMT cannot find PMT in this panel." ); } G4LogicalVolume* PanelBase::GetLogicalVolume() { if( fPanelLogical == NULL ) Log::Die("PanelBase::GetLogicalVolume: Construct has not been called."); return fPanelLogical; } void PanelBase::GetRotationAndPosition( G4RotationMatrix* rotationMatrix, G4ThreeVector* position ) { *position = fPanelOrigin; *rotationMatrix = G4RotationMatrix( fPanelXaxis, fPanelYaxis, fPanelZaxis ); *rotationMatrix = rotationMatrix->inverse(); } void PanelBase::PlacePMTs( const bool checkOverlaps ) { for( vector< PanelPMT >::const_iterator iTer = fPMTs.begin(); iTer != fPMTs.end(); ++iTer ) { if( iTer->fEnvelope == NULL ) continue; std::string pmtName = fPrefix + std::string( "_pmtenv" ) + ::to_string( iTer->fID ); // Need to rotate PMT to align it with the panel axis G4RotationMatrix* localRotation = new G4RotationMatrix(); localRotation->rotateZ( fPMTRotation ); new G4PVPlacement( localRotation, iTer->fPos, iTer->fEnvelope->GetLogicalVolume(), pmtName, fPanelLogical, false, iTer->fID, checkOverlaps ); } } void PanelBase::CutPMTs() { // Construct the base shape to cut out const int nPoints = 2; double z[nPoints], rInner[nPoints], rOuter[nPoints]; z[0] = fPanelHeight + 3.0 * kOverlapGap; z[1] = fPanelDepth - 3.0 * kOverlapGap; rInner[0] = rInner[1] = 0.0; rOuter[0] = rOuter[1] = fPMTRadius + 3.0 * mm - kOverlapGap; const G4int numHexEdges = 6; G4Polyhedra* baseSolid = new G4Polyhedra( fPrefix + "_cut_solid", 0, twopi, numHexEdges, nPoints, z, rInner, rOuter ); G4VSolid* panel = fPanelLogical->GetSolid(); for( vector< PanelPMT >::const_iterator iTer = fPMTs.begin(); iTer != fPMTs.end(); ++iTer ) { if( iTer->fEnvelope != NULL ) continue; // No Need to rotate PMT to align it with the panel axis G4RotationMatrix* localRotation = new G4RotationMatrix(); localRotation->rotateZ( fPMTRotation ); panel = new G4SubtractionSolid( fPrefix, panel, baseSolid, localRotation, iTer->fPos ); } fPanelLogical->SetSolid( panel ); } void PanelBase::CutEdge() { // Construct the base shape to cut out const int nPoints = 2; double z[nPoints], rInner[nPoints], rOuter[nPoints]; z[0] = fPanelHeight + 3.0 * kOverlapGap; z[1] = fPanelDepth - 3.0 * kOverlapGap; rInner[0] = rInner[1] = 0.0; rOuter[0] = rOuter[1] = fPMTRadius + 3.0 * mm - kOverlapGap; const G4int numHexEdges = 6; G4Polyhedra* baseSolid = new G4Polyhedra( fPrefix + "_cut_solid", 0, twopi, numHexEdges, nPoints, z, rInner, rOuter ); G4VSolid* panel = fPanelLogical->GetSolid(); for( vector::const_iterator iTer = fEdgeCoords.begin(); iTer != fEdgeCoords.end(); ++iTer ) { // No Need to rotate PMT to align it with the panel axis G4RotationMatrix* localRotation = new G4RotationMatrix(); localRotation->rotateZ( fPMTRotation ); panel = new G4SubtractionSolid( fPrefix, panel, baseSolid, localRotation, *iTer ); } fPanelLogical->SetSolid( panel ); }