#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __GNUC__ #define UNUSED __attribute__((unused)) #else #define UNUSED #endif using namespace CLHEP; using namespace std; namespace RAT { void GeoCanSourceFactory::Construct(DBLinkPtr table, UNUSED const bool checkOverlaps){ string motherName = table->GetS("mother"); G4VPhysicalVolume *motherPhys = Detector::FindPhysicalVolume( motherName ); // Position of the can G4ThreeVector canPosition(0.0,0.0,47.5); try{const vector &pos = table->GetFArrayFromD("canPosition"); size_t nArgs = pos.size(); if(nArgs==3){canPosition.setX(pos[0] * mm); canPosition.setY(pos[1] * mm); canPosition.setZ(pos[2] * mm);} else{warn << "Warning: Source can position not completely specified as" << " [x,y,z]. Using default instead." << endl;} } catch(DBNotFoundError &e){}; // Dimensions of various can components fpmtRadius = 5.25; try{fpmtRadius = table->GetD("pmtRadius");} catch(DBNotFoundError &e){}; fpmtHeight = 45.0; try{fpmtHeight = table->GetD("pmtHeight");} catch(DBNotFoundError &e){}; fpmtBaseRadius = fpmtRadius; try{fpmtBaseRadius = table->GetD("pmtBaseRadius");} catch(DBNotFoundError &e){}; fpmtBaseHeight = 50.0; try{fpmtBaseHeight = table->GetD("pmtBaseHeight");} catch(DBNotFoundError &e){}; flightGuideHeight = 0.0; try{flightGuideHeight = table->GetD("lightGuideHeight");} catch(DBNotFoundError &e){}; // So we don't try to build a lightguide of zero height... if(flightGuideHeight == 0.0) fbuildLightGuide = false; finnerCanThickness = 2.0; try{finnerCanThickness = table->GetD("innerCanThickness");} catch(DBNotFoundError &e){}; fouterCanThickness = 2.0; try{fouterCanThickness = table->GetD("outerCanThickness");} catch(DBNotFoundError &e){}; fbuttonRadius = fpmtRadius; try{fbuttonRadius = table->GetD("buttonRadius");} catch(DBNotFoundError &e){}; fbuttonThickness = 4.0; try{fbuttonThickness = table->GetD("buttonThickness");} catch(DBNotFoundError &e){}; // Dimensions of volumes are relative to size of pmt and button finnerCanHalfHeight = (fpmtHeight+fpmtBaseHeight+flightGuideHeight+ fbuttonThickness)/2.0+ finnerCanThickness; fouterCanHalfHeight = finnerCanHalfHeight+fouterCanThickness; finnerCanRadius = max(max(fpmtRadius,fpmtBaseRadius),fbuttonRadius)+ finnerCanThickness; fouterCanRadius = finnerCanRadius+fouterCanThickness; G4Tubs *outerCan = new G4Tubs("outerCan",0.0,fouterCanRadius, fouterCanHalfHeight,0.0,twopi); G4Tubs *innerCan = new G4Tubs("innerCan",0.0,finnerCanRadius, finnerCanHalfHeight,0.0,twopi); G4Tubs *pmt = new G4Tubs("pmt",0.0,fpmtRadius, fpmtHeight/2.0,0.0,twopi); G4Tubs *pmtBase = new G4Tubs("pmtBase",0.0,fpmtBaseRadius, fpmtBaseHeight/2.0,0.0,twopi); G4Tubs *button = new G4Tubs("button",0.0,fbuttonRadius, fbuttonThickness/2.0,0.0,twopi); // The materials for the various components G4Material *outerCanMaterial = G4Material::GetMaterial("G4_POLYOXYMETHYLENE"); try{outerCanMaterial = G4Material::GetMaterial( table->GetS("outerCanMaterial"));} catch(DBNotFoundError &e){}; G4Material *innerCanMaterial = G4Material::GetMaterial("G4_POLYOXYMETHYLENE"); try{innerCanMaterial = G4Material::GetMaterial( table->GetS("innerCanMaterial"));} catch(DBNotFoundError &e){}; G4Material *pmtMaterial = G4Material::GetMaterial("cansource_pmtglass"); G4Material *pmtBaseMaterial = G4Material::GetMaterial("cansource_pmtbase"); G4Material *buttonMaterial = G4Material::GetMaterial( "G4_PLASTIC_SC_VINYLTOLUENE"); // Create logical volumes G4LogicalVolume *outerCanLog = new G4LogicalVolume(outerCan,outerCanMaterial, "outerCan"); G4LogicalVolume *innerCanLog = new G4LogicalVolume(innerCan,innerCanMaterial, "innerCan"); G4LogicalVolume *pmtLog = new G4LogicalVolume(pmt,pmtMaterial, "pmtCan"); G4LogicalVolume *pmtBaseLog = new G4LogicalVolume(pmtBase,pmtBaseMaterial, "pmtBaseCan"); G4LogicalVolume *buttonLog = new G4LogicalVolume(button,buttonMaterial, "button"); // Give the volumes some colours for visualization G4VisAttributes *outerCanCol = new G4VisAttributes(G4Colour(0.0,1.0,0.0)); G4VisAttributes *innerCanCol = new G4VisAttributes(G4Colour(1.0,0.0,1.0)); G4VisAttributes *pmtCol = new G4VisAttributes(G4Colour(1.0,0.0,0.0)); G4VisAttributes *pmtBaseCol = new G4VisAttributes(G4Colour(0.0,0.0,1.0)); G4VisAttributes *buttonCol = new G4VisAttributes(G4Colour(1.0,1.0,0.0)); outerCanLog->SetVisAttributes(outerCanCol); innerCanLog->SetVisAttributes(innerCanCol); pmtLog->SetVisAttributes(pmtCol); pmtBaseLog->SetVisAttributes(pmtBaseCol); buttonLog->SetVisAttributes(buttonCol); // Create and position the physical volumes // The outer can is positioned in the mother specified in the geo file // G4VPhysicalVolume *outerCanPhys = new G4PVPlacement(0, new G4PVPlacement(0,canPosition,outerCanLog->GetName(),outerCanLog, motherPhys,false,0); // The inner can is placed at the centre of the outer can float finnerCanX = 0.0; float finnerCanY = 0.0; float finnerCanZ = 0.0; G4ThreeVector innerCanPosition(finnerCanX,finnerCanY,finnerCanZ); // G4VPhysicalVolume *innerCanPhys = new G4PVPlacement(0, new G4PVPlacement(0,innerCanPosition,innerCanLog,innerCanLog->GetName(), outerCanLog,false,0); // Shift the pmt up in Z by half the light guide thickness plus half the // button thickness minus half the pmt base // height float fpmtX = 0.0; float fpmtY = 0.0; float fpmtZ = (flightGuideHeight+fbuttonThickness-fpmtBaseHeight)/2.0; G4ThreeVector pmtPosition(fpmtX,fpmtY,fpmtZ); new G4PVPlacement(0,pmtPosition,pmtLog,pmtLog->GetName(), innerCanLog,false,0); // Shift the pmt base up in Z by half the button thickness plus half the // lightguide height plus half the pmt height float fpmtBaseX = 0.0; float fpmtBaseY = 0.0; float fpmtBaseZ = (fbuttonThickness+fpmtHeight+flightGuideHeight)/2.0; G4ThreeVector pmtBasePosition(fpmtBaseX,fpmtBaseY,fpmtBaseZ); new G4PVPlacement(0,pmtBasePosition,pmtBaseLog,pmtBaseLog->GetName(), innerCanLog,false,0); // Shift the button down in Z by half the pmt plus half the pmt base plus half // the lightguide height float fbuttonX = 0.0; float fbuttonY = 0.0; float fbuttonZ = -(fpmtHeight+fpmtBaseHeight+flightGuideHeight)/2.0; G4ThreeVector buttonPosition(fbuttonX,fbuttonY,fbuttonZ); new G4PVPlacement(0,buttonPosition,buttonLog,buttonLog->GetName(), innerCanLog,false,0); // Build the lightguide only if it has a non-zero length... if(fbuildLightGuide){ // By default, the lightguide is a cone, with radius equal to the button radius // on the side that contacts the button, and radius equal to the pmt radius on // the side that contacts the pmt flightGuideButtonRadius = fbuttonRadius; try{flightGuideButtonRadius = table->GetD("lightGuideButtonRadius");} catch(DBNotFoundError &e){}; flightGuidePmtRadius = fpmtRadius; try{flightGuidePmtRadius = table->GetD("lightGuidePmtRadius");} catch(DBNotFoundError &e){}; G4Cons *lightGuide = new G4Cons("lightGuide",0.0,flightGuideButtonRadius, 0.0,flightGuidePmtRadius, flightGuideHeight/2.0,0.0,twopi); G4Material *lightGuideMaterial = G4Material::GetMaterial("acrylic_sno"); G4LogicalVolume *lightGuideLog = new G4LogicalVolume(lightGuide, lightGuideMaterial,"lightGuide"); G4VisAttributes *lightGuideCol = new G4VisAttributes(G4Colour(0.0,1.0,1.0)); lightGuideLog->SetVisAttributes(lightGuideCol); // Shift the lightguide up in Z by half the button thickness minus half the pmt // base height minus half the pmt height (likely a negative number, so a // downward shift) double flightGuideX = 0.0; double flightGuideY = 0.0; double flightGuideZ = (fbuttonThickness-fpmtBaseHeight-fpmtHeight)/2.0; G4ThreeVector lightGuidePosition(flightGuideX,flightGuideY,flightGuideZ); new G4PVPlacement(0,lightGuidePosition,lightGuideLog, lightGuideLog->GetName(), innerCanLog,false,0); } // build lightguide if return; } } // namespace RAT