//////////////////////////////////////////////////////////////////////////////// /// /// SNORope.cc /// Created on: Apr 27, 2014 /// Author: Aksel Hallin /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace RAT; SNORope::SNORope(const G4String &aTitle): SphericalSubregionList(aTitle ){ //6056.118 is the outer radius of the AV and 6084.058 is the outer radius of the rope net- they define the ropenet shell that we consider RAT::DBLinkPtr geoDimensionsTable = RAT::DB::Get()->GetLink( "NATIVE_GEO_DIMENSIONS", "natgeo_dimensions" ); G4double fInnerAVradius = geoDimensionsTable->GetD( "inner_av_radius" ); G4double fOuterAVradius = fInnerAVradius + geoDimensionsTable->GetD( "av_thickness" ); G4double fDownRopeFlatRadius = geoDimensionsTable->GetD( "down_rope_flatradius" ); fDownRopeRadius = geoDimensionsTable->GetD( "down_rope_radius" ); InitializeSubregion(fOuterAVradius, fOuterAVradius+2*fDownRopeFlatRadius,kAbstract); G4double fAVthickness = geoDimensionsTable->GetD( "av_thickness" ); G4double fSNORopeRadius = geoDimensionsTable->GetD("sno_rope_radius"); fPSUPradius = geoDimensionsTable->GetD("psup_radius"); fUpRopeRadius = geoDimensionsTable->GetD( "up_rope_radius" ); fAVRadius = fOuterAVradius + geoDimensionsTable->GetD("rope_tolerance"); fRopeCylinderRadius = fInnerAVradius + fAVthickness/2. + fSNORopeRadius; fDownZMax=0.0; fUpZMin=0.0; fUpZMax=sqrt(fPSUPradius*fPSUPradius-fRopeCylinderRadius*fRopeCylinderRadius); fDownZMin=-sqrt(fPSUPradius*fPSUPradius-pow(fAVRadius+fDownRopeRadius,2)); fPhiMapOffset=fDownRopeRadius/fRopeCylinderRadius*1.01*180.0/CLHEP::pi; int i,j; for(i=0;i<360;i++){ fRopePosition[i]=NULL; fRopeZMin[i]=1e9; fRopeZMax[i]=-1e9; fRopeRadius[i]=0; } for(i=0;i<10;i++)for(j=0;j<2;j++){ double phi=(i*36+4.725*2*(j-0.5)); //4.725 degrees between upward ropes and center of whiffle tree; 10 whiffle trees 36 degrees apart int n=floor(phi+fPhiMapOffset); if(n<0)n+=360; fRopePosition[n]=new G4ThreeVector(); fRopePosition[n]->setRThetaPhi(fRopeCylinderRadius,CLHEP::halfpi,phi*CLHEP::pi/180); fRopeRadius[n]=fUpRopeRadius; fRopeZMax[n]=fUpZMax; fRopeZMin[n]=fUpZMin; } for(i=0;i<20;i++){ double phi=9+i*18; //downward ropes are 18 degrees apart, starting at 9 degrees. int n=floor(phi+fPhiMapOffset); //note fPhiMapOffset is a little more than half a rope radius angle- makes each bin have only one rope. if(n<0)n+=360; fRopePosition[n]=new G4ThreeVector(); fRopePosition[n]->setRThetaPhi(fAVRadius+fDownRopeRadius,CLHEP::halfpi,phi*CLHEP::pi/180); fRopeRadius[n]=fDownRopeRadius; fRopeZMax[n]=fDownZMax; fRopeZMin[n]=fDownZMin; } fRadii[0]=fRopeCylinderRadius-fUpRopeRadius; fRadii[1]=fAVRadius+2*fDownRopeRadius; fThreshold = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); std::listlist; for(i=0;i<10;i++){fRopeLoop[i]=new SNORopeLoop(geoDimensionsTable, i*CLHEP::pi/5);list.push_front(fRopeLoop[i]);} for(i=0;i<10;i++){ fRopeNet[i]=new SNORopeNet(geoDimensionsTable, CLHEP::pi*(27+i*36)/180.); list.push_front(fRopeNet[i]); } for(i=0;i<10;i++){ fSpreaderRope[i]=new SNOSpreaderRope(geoDimensionsTable,CLHEP::pi*(9+i*36)/180.); list.push_front(fSpreaderRope[i]); } AddRegions(list); fRminNet=fRopeNet[0]->GetRmin(); fRmaxNet=fRopeNet[0]->GetRmax(); } void SNORope::CalculateCylindricalPoints(const G4ThreeVector &aPosition, const G4ThreeVector &aDirection, G4double distances[4][2],std::list &list)const{ double a,b,c,r2,q,d; //solve quadratic equation ad**2+b*d +c=0; with discriminant q, to solve (aPosition +d*aDirection)**2=fRadii[ii]**2. int i; list.clear(); b = (aPosition.x()*aDirection.x()+aPosition.y()*aDirection.y()); //note we drop the factor of 2 here and in the solution formula a = aDirection.x()*aDirection.x()+aDirection.y()*aDirection.y(); r2=aPosition.x()*aPosition.x()+aPosition.y()*aPosition.y(); for (i = 0; i<2; i++){ c=(r2-fRadii[i]*fRadii[i]); q=b*b-a*c; if(q>0){ q=sqrt(q); d=(-b+q)/a; distances[i][0]=d; if(d>0){list.push_front(d);} d=(-b-q)/a; distances[i][1]=d; if(d>0){list.push_front(d); } }else if(q==0){ distances[i][0]=-b; distances[i][1]=-100; if(b<0){list.push_front(-b);} }else{ distances[i][0]=-100; distances[i][1]=-100; } } list.sort(); } void SNORope::CalculateCylindricalPoints(const G4ThreeVector &aPosition, const G4ThreeVector &aDirection, G4double aRadius, G4double &dist)const{ double a,b,c,r2,q,d,d2; //solve quadratic equation ad**2+b*d +c=0; with discriminant q, to solve (aPosition +d*aDirection)**2=fRadii[ii]**2. // This routine calculates intersections with an arbitrary radius. Use it to find the Rope intersection, for instance... // next is filled with the position of the next positive distance intersection. b = (aPosition.x()*aDirection.x()+aPosition.y()*aDirection.y()); //note we drop the factor of 2 here and in the solution formula a = aDirection.x()*aDirection.x()+aDirection.y()*aDirection.y(); r2=aPosition.x()*aPosition.x()+aPosition.y()*aPosition.y(); d=1e8; c=(r2-aRadius*aRadius); q=b*b-a*c; if(q>0){ q=sqrt(q); d=(-b+q)/a; if(d<0)d=1e8; d2=(-b-q)/a; if(d2>0 &&d2zmin+fThreshold){ double rho=(p-*rope).rho(); if(rho list; double distances[4][2]; CalculateCylindricalPoints(p,v,distances,list); std::list::iterator aa; if(list.empty())return kInfinity; G4ThreeVector test; int i; double dist=kInfinity; int philist[4]; G4ThreeVector next,n; n=v.cross(G4ThreeVector(0,0,1));n=n.unit(); //Go through the list of distances. int iphi; if(p.rho()>=fRadii[0]&& p.rho()<=fRadii[1]){ iphi=floor(p.phi()*360/CLHEP::twopi+fPhiMapOffset); i=1; philist[0]=iphi<0? (iphi+360)%360:iphi%360; }else i=0; for(aa=list.begin();aa!=list.end(); aa++){ double checkdist=*aa; test=p+checkdist*v; iphi=floor(test.phi()*360/CLHEP::twopi+fPhiMapOffset); philist[i++]=iphi<0? (iphi+360)%360:iphi%360; } int step=(test*n)>0?1:-1; //rho dot (v cross z) has the same sign as the rotation int k; if(philist[1]==philist[0]){philist[1]=(philist[0]+step)%360; if(philist[1]<0)philist[1]+=360;} for(k=philist[0];k!=philist[1];){ if(k==356){ test=p; } if(fRopePosition[k]!=NULL){ test=p-*fRopePosition[k]; if(fabs(test*n)fRopeZMin[k]&&next.z()2){ if(philist[i-1]==philist[i-2]){philist[i-1]=(philist[i-2]+step)%360; if(philist[i-1]<0)philist[i-1]+=360;} for(k=philist[i-2];k!=philist[i-1];){ if(fRopePosition[k]!=NULL){ test=p-*fRopePosition[k]; if(fabs(test*n)fRopeZMin[k]&&next.z()zmax-test.z())dist=zmax-test.z(); if(dist>test.z()-zmin)dist=test.z()-zmin; }else{ //debug dist=fabs(fRopeCylinderRadius-p.rho()); } double dist2=SphericalSubregionList::DistanceToOut(p); if(dist2pVoxelLimit.GetMaxXExtent()+kCarTolerance) || (xMaxpVoxelLimit.GetMaxXExtent()) { xMax=pVoxelLimit.GetMaxXExtent(); } } } yoffset=pTransform.NetTranslation().y(); yMin=yoffset-rmax; yMax=yoffset+rmax; if (pVoxelLimit.IsYLimited()) { if ( (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance) || (yMaxpVoxelLimit.GetMaxYExtent()) { yMax=pVoxelLimit.GetMaxYExtent(); } } } zoffset=pTransform.NetTranslation().z(); zMin=zoffset-rmax; zMax=zoffset+rmax; if (pVoxelLimit.IsZLimited()) { if ( (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance) || (zMaxpVoxelLimit.GetMaxZExtent()) { zMax=pVoxelLimit.GetMaxZExtent(); } } } // Known to cut sphere switch (pAxis) { case kXAxis: yoff1=yoffset-yMin; yoff2=yMax-yoffset; if ((yoff1>=0) && (yoff2>=0)) { // Y limits cross max/min x => no change // pMin=xMin; pMax=xMax; } else { // Y limits don't cross max/min x => compute max delta x, // hence new mins/maxs // delta=rmax*rmax-yoff1*yoff1; diff1=(delta>0.) ? std::sqrt(delta) : 0.; delta=rmax*rmax-yoff2*yoff2; diff2=(delta>0.) ? std::sqrt(delta) : 0.; maxDiff=(diff1>diff2) ? diff1:diff2; newMin=xoffset-maxDiff; newMax=xoffset+maxDiff; pMin=(newMinxMax) ? xMax : newMax; } break; case kYAxis: xoff1=xoffset-xMin; xoff2=xMax-xoffset; if ((xoff1>=0) && (xoff2>=0)) { // X limits cross max/min y => no change // pMin=yMin; pMax=yMax; } else { // X limits don't cross max/min y => compute max delta y, // hence new mins/maxs // delta=rmax*rmax-xoff1*xoff1; diff1=(delta>0.) ? std::sqrt(delta) : 0.; delta=rmax*rmax-xoff2*xoff2; diff2=(delta>0.) ? std::sqrt(delta) : 0.; maxDiff=(diff1>diff2) ? diff1:diff2; newMin=yoffset-maxDiff; newMax=yoffset+maxDiff; pMin=(newMinyMax) ? yMax : newMax; } break; case kZAxis: pMin=zMin; pMax=zMax; break; default: break; } pMin-=kCarTolerance; pMax+=kCarTolerance; return true; } G4GeometryType SNORope::GetEntityType(void)const{ return G4String("SNORope");} std::ostream& SNORope::StreamInfo( std::ostream& os ) const { G4int oldprc = os.precision(16); os << "-----------------------------------------------------------\n" << " *** Dump for solid - " << GetName() << " ***\n" << " ===================================================\n" << " Solid type: SNORope\n" << " No variable parameters! \n" << "-----------------------------------------------------------\n"; os.precision(oldprc); return os; } ///////////////////////////////////////////////////////////////////////////// // // Methods for visualisation #include "G4VisExtent.hh" G4VisExtent SNORope::GetExtent() const { double r=fRadii[1]+40; return G4VisExtent(-r, r,-r, r,-fPSUPradius, fPSUPradius ); } #include "G4VGraphicsScene.hh" void SNORope::DescribeYourselfTo ( G4VGraphicsScene& scene ) const { scene.AddSolid (*this); } #include "G4Polyhedron.hh" #include "Randomize.hh" using namespace CLHEP; G4ThreeVector SNORope::GetPointOnSurface()const{ double downToUpAreaRatio=(fDownZMax-fDownZMin)/(fUpZMax-fUpZMin)*fDownRopeRadius/fUpRopeRadius; double upFraction=1/(1+downToUpAreaRatio); double phi=RandFlat::shoot(0.0, CLHEP::twopi); int i=(int)RandFlat::shoot(0.0,20.0); G4ThreeVector pos; if(RandFlat::shoot(0.0,1)