c release c c Example code for using the 2dFGRS survey masks. c c Given ra and dec in radians (B1950), it returns the completeness, the c magnitude limit, the mu value and the APM plate number of that c particular area. c N.B.: c - when compl = -1., the given position is outside the main 2dF boundary c - when compl = -2., the given position is inside a drill hole c c Usage: release ra dec (where ra and dec are in radians) program release *************************************variables******************************** implicit none integer iplate,ix,iy real ra,dec,compl,maglim,muval real*8 decdble,radble character reg*3 ****************************************************************************** call getdble(1,radble) call getdble(2,decdble) ra=real(radble) dec=real(decdble) call which_reg(ra,dec,reg) write(0,*) 'Region: ',reg call in_2df_mask_reg(radble,decdble,reg,compl,maglim,muval,ix,iy) call fnumber(ra,dec,iplate) write(0,*) 'Position: ra = ',ra,' ; dec = ',dec write(0,*) 'Compl:',compl,' maglim:',maglim,' muval:',muval &, ' plate:',iplate end c----------------------------------------------------------------------------- c Reads an input as a real subroutine getdble(i,d) *************************************variables******************************** implicit none integer i real*8 d character a*100 ****************************************************************************** call getarg(i,a) read(a,*) d return end c---------------------------------------------------------------------------- c c PUBLIC MASK SOFTWARE SUBROUTINES c c---------------------------------------------------------------------------- c Given ra & dec determines which region to look at subroutine which_reg(ra,dec,reg) *************************************variables******************************** implicit none real ra,dec character reg*3 real EPS parameter (EPS=1.e-5) integer i,ifirst,nb_strip,nb_stripsgp,nb_stripngp real ra_min(4),ra_max(4),dec_min(4),dec_max(4) data ifirst/1/ save ra_min,ra_max,dec_min,dec_max,nb_strip,nb_stripsgp &, nb_stripngp,ifirst ****************************************************************************** if (ifirst.eq.1) then ifirst=0 nb_stripsgp=3 nb_stripngp=4 nb_strip=5 c SGP strips: Thanks Andrew H. for finding this bug. ra_min(3)= 5.707227 ! 21h48m ra_max(3)= 0.890118 ! 3h24m dec_min(1)= -0.479966 ! -27.5 deg dec_max(1)= -0.392699 ! -22.5 deg ra_min(2)= 5.670138 ! 21h39.5m ra_max(2)= 0.975203 ! 3h43.5m dec_min(2)= -0.567232 ! -32.5 deg dec_max(2)= -0.479966 ! -27.5 deg ra_min(1)= 5.711590 ! 21h49m ra_max(1)= 0.911935 ! 3h29m dec_min(3)= -0.654498 ! -37.5 deg dec_max(3)= -0.567232 ! -32.5 deg c NGP strips ra_min(4)= 2.574361 ! 9h50m ra_max(4)= 3.883358 ! 14h50m dec_min(4)= -0.130900 ! -7.5 deg dec_max(4)= +0.043633 ! +2.5 deg c Make boundaries more secure do i=1,4 ra_min(i)=ra_min(i)-EPS ra_max(i)=ra_max(i)+EPS dec_min(i)=dec_min(i)-EPS dec_max(i)=dec_max(i)+EPS enddo call set_pivals endif i=0 do while (i.lt.nb_stripsgp) i=i+1 if (((ra_min(i).le.ra).or.(ra_max(i).ge.ra)).and. & (dec_min(i).le.dec).and.(dec_max(i).ge.dec)) then i=nb_strip reg='sgp' endif enddo do while (i.lt.nb_stripngp) i=i+1 if ((ra_min(i).le.ra).and.(ra_max(i).ge.ra).and. & (dec_min(i).le.dec).and.(dec_max(i).ge.dec)) then i=nb_strip reg='ngp' endif enddo if (i.ne.nb_strip) reg='ran' return end c----------------------------------------------------------------------------- c For a given position in ra & dec, this subroutine tells if this c position is inside the 2df_mask or not, by returning the actual c completeness. It returns in the same time the corresponding c magnitude limit, and mu mask value. subroutine in_2df_mask_reg(ra,dec,reg,compl,maglim,muval,ix,iy) *************************************variables******************************** implicit none real compl,maglim,muval real*8 ra,dec integer np_x,np_y parameter (np_x=2*1800,np_y=2*600) integer np_xx,np_yy,ifirst,ix,iy,np,sgn real rpix(np_x,np_y),magpix(np_x,np_y),mupix(np_x,np_y) real*8 x,y,z,rx,ry character name_mask*20,last_reg*3,reg*3 save ifirst,np_xx,np_yy,np,rpix,magpix,mupix,last_reg data ifirst/1/ ****************************************************************************** if (reg.eq.'ran') then call in_2df_ran(ra,dec,compl,maglim,muval,ix,iy) return endif c On the first call, the program reads the mask if ((ifirst.eq.1).or.(last_reg.ne.reg)) then ifirst=0 last_reg=reg name_mask='mask.'//reg//'.dat' call read_mask(rpix,np_xx,np_yy,name_mask,np_x,np_y,np) name_mask='maglim.'//reg//'.dat' call read_mask(magpix,np_xx,np_yy,name_mask,np_x,np_y,np) name_mask='mumask.'//reg//'.dat' call read_mask(mupix,np_xx,np_yy,name_mask,np_x,np_y,np) write(0,*) 'Read masks for ',reg,' region!' endif call radec_xyz_dbl(ra,dec,x,y,z) call eq_2dfrx(np,x,y,z,rx,ry,sgn) call rx_ix_map(rx,ry,ix,iy) if ((ix.ge.1).and.(ix.le.np_xx).and. : (iy.ge.1).and.(iy.le.np_yy)) then compl=rpix(ix,iy) maglim=magpix(ix,iy) muval=mupix(ix,iy) else compl= -1.0 !default value (i.e. outside 2dF boundary) maglim=-2.0 !default value (i.e. outside 2dF boundary) muval=19.0 !default value (i.e. outside 2dF boundary) endif return end c----------------------------------------------------------------------------- c For a given position in ra & dec, this subroutine tells if this c position is inside one of the used random fields or not, by returning c the actual completeness of the field. subroutine in_2df_ran(ra,dec,compl,maglim,muval,ix,iy) *************************************variables******************************** implicit none integer ix,iy real*8 ra,dec real compl,maglim,muval integer nmax,NP,NPX,NPY real theta_min parameter (nmax=98,NP=2*2400,NPX=NP/48,NPY=NP/48,theta_min=1.014) logical in integer i,ifirst,nb_field real*8 costheta_r,r,x,y,z,costheta_min,costheta &, xc(nmax),yc(nmax),zc(nmax) real comp(nmax),magpix(nmax,NPX,NPY),mupix(nmax,NPX,NPY) character name_mask*20 data ifirst/1/ save ifirst,nb_field,xc,yc,zc,comp,costheta_min,magpix,mupix ****************************************************************************** c On the first call, reads the file containing the random fields if (ifirst.eq.1) then ifirst=0 name_mask='mask.ran.dat' call ran2df_cen_used_dbl(nb_field,xc,yc,zc,comp,name_mask) name_mask='maglim.ran.dat' call readranmask(name_mask,NPX,NPY,nmax,magpix) name_mask='mumask.ran.dat' call readranmask(name_mask,NPX,NPY,nmax,mupix) costheta_min=dble(cos(theta_min*atan(1.)/45.)) write(0,*) 'Read mask for ran region!' endif i=0 in=.false. call radec_xyz_dbl(ra,dec,x,y,z) r=sqrt(x**2+y**2+z**2) costheta_r=costheta_min*r do while ((.not.in).and.(i.lt.nb_field)) i=i+1 costheta=(x*xc(i)+y*yc(i)+z*zc(i)) if (costheta.gt.costheta_r) then ! We use here the fact the random in=.true. ! fields doesn't overlapp with endif ! each other... enddo if (in) then call get_pixelran(NP,NPX,NPY,x,y,z,xc(i),yc(i),zc(i),maglim &, muval,nmax,magpix,mupix,i,ix,iy) if (maglim.le.-1) then compl=-2. ! default value in holes else compl=comp(i) endif else compl=-1. ! default value (ie. outside 2dF boundary) maglim=-2. ! default value (when not specified) muval=19.0 ! default value (when not specified) endif return end c---------------------------------------------------------------------------- c Given x,y,z position and centre of the corresponding random field, c returns the magnitude limit at that position subroutine get_pixelran(NP,NPX,NPY,x,y,z,xc,yc,zc,maglim &, muval,nmax,magpix,mupix,ifield,ix,iy) implicit none integer NP,NPX,NPY,nmax,ifield real*8 x,y,z,xc,yc,zc real maglim,magpix(nmax,NPX,NPY),muval,mupix(nmax,NPX,NPY) integer sgn,ixc_min,iyc_min,ix,iy real rx,ry call eq_2dfrx(NP,xc,yc,zc,rx,ry,sgn) call bound_map_ran(NPX,NPY,rx,ry,ixc_min,iyc_min) call eq_2dfrx(NP,x,y,z,rx,ry,sgn) call rx_ix_map(rx,ry,ix,iy) ix=min(max(1,ix-ixc_min),NPX) iy=min(max(1,iy-iyc_min),NPY) if ((ix.ge.1).and.(ix.le.NPX).and.(iy.ge.1).and.(iy.le.NPY)) then maglim=magpix(ifield,ix,iy) muval=mupix(ifield,ix,iy) else maglim=-2.0 muval=19.0 endif return end c----------------------------------------------------------------------------- c This subroutine transforms ra & dec into x,y & z cartesian coordinates. subroutine radec_xyz_dbl(ra,dec,x,y,z) implicit none real*8 x,y,z,ra,dec x=cos(dec)*cos(ra) y=cos(dec)*sin(ra) z=sin(dec) return end c----------------------------------------------------------------------------- c Convert an equatorial cartesian coordinate to the rx,ry pixel c coordinate used for the 2df mask. This subroutine is valid for both c sgp and ngp elements. c c subroutine eq_2dfrx(NP,x,y,z,rx,ry,sgn) *************************************variables******************************** implicit none real*8 x,y,z,xx,yy,zz,r,phi,costheta,sintheta_2 real PI,EPS parameter (EPS=3.e-13) integer ifirst,sgn,NP,ix_min,iy_min real racen,sc,deccen,rx,ry real xc,yc,zc,dec_gc,ra_gc,xgc,ygc,zgc & ,xgp,ygp,zgp,phi0 save ifirst,sc,xc,yc,zc,xgc,ygc,zgc,xgp,ygp,zgp,phi0,PI !ix_min,iy_min data ifirst/1/ ****************************************************************************** c On the first call define the values which define the c centre, orientation and scale of the transformation if (ifirst.eq.1) then ifirst=0 PI= atan(1.)*4. c This is the direction of the Galactic Centre as adopted c by Steve Maddox racen = 12.3*PI/180.0 deccen = -27.5*PI/180.0 sc = 120.0*PI/180.0 xc=cos(deccen)*cos(racen) yc=cos(deccen)*sin(racen) zc=sin(deccen) c This is a direction perpendicular to above but otherwise c arbitrary provided that the phi0 has then been correctly c set to be the offset between this arbitrary direction and c that used for the projection of the APM SGP region ra_gc = -94.40593*PI/180.0 dec_gc = -28.90771*PI/180.0 phi0=236.97694*PI/180.0 xgc=cos(dec_gc)*cos(ra_gc) ygc=cos(dec_gc)*sin(ra_gc) zgc=sin(dec_gc) c Generate the mutually perpendicular unit vector via c the cross product xgp = yc*zgc-zc*ygc ygp = zc*xgc-xc*zgc zgp = xc*ygc-yc*xgc endif c Section utilized on each call c Find components in the new 3D Cartesian system r=sqrt(x**2+y**2+z**2) zz=(x*xc+y*yc+z*zc) xx=(x*xgc+y*ygc+z*zgc) yy=(x*xgp+y*ygp+z*zgp) c Compute corresponding spherical polar angles costheta= abs(zz/r) sgn=int(sign(1.,real(zz/r))) ! tells if x,y,z is in the ngp or sgp region phi=phi0-atan2(yy,xx) if (phi.gt.2.0*PI) phi=phi-2.0*PI c Apply the Zenithal Equal Area Projection if (real(dble(1.0)-costheta).ge.EPS) then sintheta_2=dsqrt(dble(0.5)*(dble(1.0)-costheta)) else sintheta_2=0. endif r=2.*sintheta_2 !If sc changes, change this like:r=sintheta_2/sin(sc/4.) c convert to x,y coordinate xx=-r*sin(phi)*dble(NP)*0.5 yy= r*cos(phi)*dble(NP)*0.5 call bound_map_2df(NP,sgn,ix_min,iy_min) rx=real(xx+0.5*dble(NP)-1.*dble(ix_min)) ry=real(-yy+0.5*dble(NP)-1.*dble(iy_min)) return end c----------------------------------------------------------------------------- c This subroutine contains the boundaries of the sgp and ngp pixel map. c It returns the ix_min and iy_min which are the offsets of the two maps. subroutine bound_map_2df(NP,sgn,ix_min,iy_min) ****************************************************************************** implicit none integer NP,sgn,ix_min,iy_min ****************************************************************************** if (sgn.eq.1) then ! use the sgp map ix_min=NP*15/100 iy_min=NP*44/100 else if (sgn.eq.-1) then ! use the ngp map ix_min=NP*7/100 iy_min=NP*60/100 endif return end c---------------------------------------------------------------------------- c This subroutine gives the right boundaries for each random field mask, ie. c calculates the offset needed such that the pixel center of each random c field, given by (rxc,ryc), is located at (NPX_ran/2, NPY_ran/2) . c subroutine bound_map_ran(NPX_ran,NPY_ran,rxc,ryc,ixc_min,iyc_min) implicit none integer NPX_ran,NPY_ran,ixc_min,iyc_min real rxc,ryc integer ixc,iyc call rx_ix_map(rxc,ryc,ixc,iyc) ixc_min=ixc-int(NPX_ran/2) iyc_min=iyc-int(NPY_ran/2) return end c----------------------------------------------------------------------------- c This subroutine converts real pixel coordinates rx,ry to integer c ix,iy pixel coordinates. subroutine rx_ix_map(rx,ry,ix,iy) ****************************************************************************** implicit none integer ix,iy real rx,ry ****************************************************************************** ix=int(rx+0.5) iy=int(ry+0.5) return end c----------------------------------------------------------------------------- c This subroutine sets and checks that NP and NPX_NPY are correct and that c they correspond to the value used for NPX and NPY, the dimensions of the c pixel grid. c N.B.: NPX_NPY is also accepted if equal to 0 (default value if not c used!) subroutine NP_set(NPX,NPY,NP,NPX_NPY) ****************************************************************************** implicit none integer NPX,NPY,NP,NPX_NPY integer num ****************************************************************************** NP=NPX*4/3 if (NP.ne.NPY*4) then write(0,*) 'Distortion of the pixel grid: NPX= ',NPX,' NPY=' &, NPY,' do not obey NPX=3*NPY!' stop 'NP_set' endif c We check also that NPX_NPY is NPX*NPY or NPX_NPY = 0 num=NPX*NPY if ((num.ne.NPX_NPY).and.(NPX_NPY.ne.0)) then write(0,*) 'Wrong dimension on NPX_NPY; should be ',num stop 'NP_set' endif return end c---------------------------------------------------------------------------- c Subroutine to read the 2dF mask c subroutine read_mask(mask,np_xx,np_yy,name_mask,np_x,np_y,np) *************************************variables******************************** implicit none integer np_x,np_y,np_xx,np_yy,np real mask(np_x,np_y) character name_mask*(*) integer ix,iy ****************************************************************************** open(11,file=name_mask,status='old',form='unformatted') read(11) np_xx,np_yy call NP_set(np_xx,np_yy,np,0) if ((np_xx.le.np_x).and.(np_yy.le.np_y)) then do ix=1,np_xx read(11) (mask(ix,iy),iy=1,np_yy) enddo else write(0,*) 'Dimension of the mask too big!' write(0,*) ' Mask: NPX= ',np_xx,' NPY= ',np_yy stop 'read_mask!' endif close(11) return end c----------------------------------------------------------------------------- subroutine readranmask(namemask,NPX,NPY,nbf,rpix) c This subroutine reads the mask stored in the file name_mask. c N.B.: This subroutine contains the same stuff as mask_2df, but has the c advantage of giving back also sgn! implicit none integer nbf,NPX,NPY real rpix(nbf,NPX,NPY) character namemask*(*) integer i,j,k,npxx,npyy,nbff open(unit=14,file=namemask,status='old',form='unformatted') read(14) nbff,npxx,npyy if ((npxx.ne.NPX).or.(npyy.ne.NPY).or.(nbff.ne.nbf)) then write(*,*) 'Wrong dimensions for ran mask. Should have:' &, npxx,npyy,nbff stop 'readranmask' endif do k=1,nbff do i=1,npxx read(14) (rpix(k,i,j),j=1,npyy) enddo enddo close(14) return end c---------------------------------------------------------------------------- c This subroutine reads the used 2dF random field centres from the file c name, which contains also the overall completeness of the field (with c respect to the underlying density field). It is a real*8 version c of ran2df_cen_used. subroutine ran2df_cen_used_dbl(nb_field,xc,yc,zc,comp,name) *************************************variables******************************** implicit none integer nb_field real comp(*) real*8 xc(*),yc(*),zc(*) character name*(*) integer i ****************************************************************************** open(unit=11,file=name,status='old',form='unformatted') read(11) nb_field read(11) (comp(i),i=1,nb_field) do i=1,nb_field xc(i)=dble(comp(i)) enddo read(11) (comp(i),i=1,nb_field) do i=1,nb_field yc(i)=dble(comp(i)) enddo read(11) (comp(i),i=1,nb_field) do i=1,nb_field zc(i)=dble(comp(i)) enddo read(11) (comp(i),i=1,nb_field) close(11) return end c----------------------------------------------------------------------------- c c DO NOT ADD THE FOLLOWING ROUTINES IF THIS FILE IS COMBINED WITH HOLES.F c c----------------------------------------------------------------------------- subroutine fnumber(rar,decr,ifield) c c given ra,dec in radians returns corresponding field no. c implicit none integer ifield real decr,rar integer iygrid,ixgrid,i real ra,dec,raminus,yspace,ygrid,xspace,xgrid,xoff,yoff &, xspace348,ratest348,edge348 integer*4 field0h(22) real*4 ragaps(22), decbands(22) data (ragaps(i),i=1,22)/ 0.,144.,90.,66.,52.,44.,38.,33.,30.,28., + 26.,24.,23.,22.,21.,20.,20.,20.,20.,20.,20.,20./ data (decbands(i),i=1,22)/-90.,-85.,-80.,-75.,-70.,-65.,-60.,-55., + -50.,-45.,-40.,-35.,-30.,-25.,-20.,-15.,-10.,-5.,0.,5.,10.,15./ data (field0h(i),i=1,22)/1,2,12,28,50,78,111,149,193,241,293,349, + 409,472,538,607,679,751,823,895,967,1039 / real pival,degs_rads,ramins_rads,radfac,tpi common/pivals/ pival,degs_rads,ramins_rads,radfac,tpi c find the nearest grid centre ra = rar*180./pival dec = decr*180./pival if (dec.gt.15.) then ifield = 0 return end if if (ra.lt.0.) ra = ra + 360. if (ra.gt.180.) then raminus = ra - 360. else raminus = ra end if yspace = 5.0 iygrid = nint(dec/5.)+19 ygrid = decbands(iygrid) xspace = ragaps(iygrid) if (abs(raminus).lt.xspace/4.0/2.0) then ! 4 for degs, 2 for half field c it's a 0hr field xgrid = 0. ixgrid = 0 else xspace = ragaps(iygrid) / 4.0 ! in degs ixgrid = int(ra/xspace + 0.5) xgrid = ixgrid * xspace end if ifield = field0h(iygrid) + ixgrid c Do we really need this part???? Apparently for the SGP region... xspace348 = 26 ratest348 = 0.5*xspace348*ramins_rads edge348 = -10.*ramins_rads +ratest348 if(ifield.eq.293 .and. raminus.le.edge348) then ifield=348 xgrid = -10*xspace348 end if c ????? xoff = ra - xgrid if (xoff.gt.180.) xoff = xoff - 360. yoff = dec - ygrid c type*,'Field no. = ',ifield c type*,'RA , Dec offset = ',xoff,yoff return end c--------------------------------------------------------------------------- subroutine set_pivals c Initialisation of some constants for these routines implicit none real pival,degs_rads,ramins_rads,radfac,tpi common/pivals/ pival,degs_rads,ramins_rads,radfac,tpi pival = atan(1.)*4. degs_rads = pival/180.0 ramins_rads = pival/(12.*60.) radfac = 2.*pival/360./60. tpi = 2.*pival return end