#!/usr/bin/env isis-script private variable Script_Version_String = "1.0.0"; % pile_estimate.sl 2010 April 23 % % This file is the pile_estimate routine and associated software. % Copyright (C) 2008 Massachusetts Institute of Technology % Author: Michael A. Nowak, mnowak@alum.mit.edu % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2 of the License, or % (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % Program requires: ISIS, & the S-Lang cmdopt, XPA, & GTK modules. % ("vwhere" is part of the GTK module.) % cmdopt module is normally bundled with S-lang and/or ISIS. % See the ISIS web page: http://space.mit.edu/cxc/isis/index.html % And the S-lang modules page: http://space.mit.edu/cxc/software/slang/modules % vwhere for lightcurve filtering define vwhere(); variable nofilter = 0; variable show_select =0; try { require("vwhere"); } catch AnyError: { nofilter = 1; ()=fprintf(stderr, "** Warning: Unable to import the gtk module (vwhere), assuming --nofilter\n"); } % DS9 for displaying - requires the XPA module autoload("ds9_new","ds9object"); % Taken from John Davis's aeattcor.sl private define open_ds9 () { variable e, ds9 = NULL; try (e) { ds9 = ds9_new(sprintf("ds9.%s.%d", path_basename(__argv[0]), getpid()); verbose=1, timeout=90); } catch AnyError: { ()=fprintf (stderr, "** Warning: Unable to open ds9: %S\n", e.message); } return ds9; } % cmdopt module for parsing the command line require("cmdopt"); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % A simple boxcar 3x3 convolution written by John Davis private define conv3x3 (img) { % An FFT may be faster but this is simple variable dims = array_shape (img); variable n0 = dims[0]; variable n1 = dims[1]; variable i = [0:n0-1]; variable j = [0:n1-1]; variable i0 = (i-1); variable j0 = (j-1); variable i1 = (i+1) mod n0; variable j1 = (j+1) mod n1; variable img1 = @img; img1[i,j] += img[i0,j0]; img1[i,j] += img[i0,j]; img1[i,j] += img[i0,j1]; img1[i,j] += img[i,j0]; img1[i,j] += img[i,j1]; img1[i,j] += img[i1,j0]; img1[i,j] += img[i1,j]; img1[i,j] += img[i1,j1]; return __tmp(img1) / 9.0f; } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % A simple program written by John Davis to watch for a key input private define getkey() { ()=system("stty raw"); variable ch; if(1 != read(fileno(stdin), &ch, 1)) ch=0; ()=system("stty sane"); return ch; } %%%%%%%%%%%%%%%%%%%%%%%%%%% private define exit_usage() { variable fp = stderr; ()=fprintf (fp, "\nUsage: %s [options] evtfile\n",__argv[0]); ()=fprintf (fp, "\n%s\n", %{{{ +" Create a pileup map out of the Suzaku event data in `evtfile'. A rate\n" +" lightcurve will be created in 3 energy bins (ra, rb, rc). Unless the\n" +" --nofilter option has been chosen, these data will be passed to `vwhere',\n" +" which can be used to select times of uniform rate and colors. Time\n" +" selections are printed to screen and written to a file, e.g., for xselect.\n" +"\n" +" A box-car smoothed (3x3 pixel bins) image is displayed, with the image\n" +" rescaled to be the *estimated* pileup fraction. Pileup fraction\n" +" here is defined to be the ratio of events lost via grade *or* energy\n" +" migration to the events expected in the absence of pileup. The\n" +" image displays discrete steps that represent the *minimum* pileup\n" +" fraction in the displayed region, with the exception of the highest\n" +" displayed value. This value corresponds to the image maximum, and is\n" +" shown over regions at this maximum down to half way towards the next\n" +" lowest displayed value. (A continuous pileup image can be displayed by\n" +" using the --cont-pfrac option.).\n" +"\n" +" One can quit without proceeding further, or create a region file. Any\n" +" combination circular, elliptical, box, and annular exclude/include regions\n" +" are supported, so long as there is at least one include region. Include\n" +" regions are applied first, and then the exclude regions are applied.\n" +" Regions must be in physical coordinates and use the ds9/funtools format.\n" +" Choosing 'y' will automatically save the region to a file, and the\n" +" --show_select option redraws the image with the region selection applied.\n" +"\n" +" Using the time and region filtered events, an estimate is made of the\n" +" values to which one should set pileup parameters (frame time, number\n" +" of regions, PSF fraction) if fitting the filtered events with the ISIS\n" +" pileup model. Values are printed to a file. (This is experimental, and\n" +" may not be 100\% quantitatively accurate.)\n" +"\n" +" Options (must precede input evtfile; arrays/ranges do not use () or []):\n" +"\n" +" --nofilter\n" +" The selection of events with `vwhere' is skipped.\n" +" If the gtk module is not installed, --nofilter is the default.\n" +" --tbin=val\n" +" The lightcurve is created with time bins of the total frame time\n" +" (exposure, plus delay time, e.g., for burst mode observations),\n" +" multiplied by an integer binning factor, tbin. Rates, however,\n" +" are per exposure time. [Default=16]\n" +" --save-lightcurve=val\n" +" Save lightcurve into FITS file (ignored, if --nofilter is chosen).\n" +" --pfrac=vals\n" +" The minimum fractional pileup levels for the discretized pileup\n" +" image. [Default=0.01,0.02,0.05,0.1]\n" +" --cont-pfrac\n" +" Show a continuous image of the fractional pileup.\n" +" (The --pfrac option is ignored if --cont-pfrac is used.)\n" +" --only-save-pileup-img=val\n" +" The estimated pileup fraction is only saved as a FITS image,\n" +" but not displayed through ds9.\n" +" --show-select\n" +" Display the pileup image with selections applied at the end.\n" +" --outfile=val\n" +" The root name for the output files, i.e., val.flt (time filter),\n" +" val.reg (region file), val.parms (suggested pileup parameters).\n" +" [Default=input file name]\n" +" --filter-file=val\n" +" (Optional input.) The name of a file containing pairs of times to\n" +" be considered good times. Creates a new column, filter, that is \n" +" passed to vwhere. This column will contain 1's for times within \n" +" these GTI values, and 0's for times outside of them. This allows\n" +" one to apply previously defined filters to the data. [default=NULL]\n" +" --a-band=vals [default: 0.5-1.5]\n" +" --b-band=vals [default: 1.5-3]\n" +" --c-band=vals [default: 3-9]\n" +" The energy bands (keV) for the three colors in the lightcurve,\n" +" specified as 'lo-hi', or, equivalently, 'lo,hi'\n" +" --alpha=val\n" +" The usual pileup alpha parameter (see the Chandra ABC Guide to\n" +" Pileup, or Davis 2001, ApJ, 562, 575). Affects the estimated\n" +" pileup fractions and suggested model parameters [Default=0.5]\n" +" -v, --version\n" +" Print version.\n" +" -h, --help\n" +" This message.\n"); %}}} exit(1); } %%%%%%%%%%%%%%%%%%%%%%%%%%%%% private define exit_version() { ()=fprintf(stdout, "Version: %S\n", Script_Version_String); exit (0); } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Define the types of regions we will parse from DS9. Find the points % on the interior of the regions. define rotate(xpix,ypix,xcent,ycent,angl) { angl *= PI/180.; return cos(angl)*(xpix-xcent) + sin(angl)*(ypix-ycent), -sin(angl)*(xpix-xcent) + cos(angl)*(ypix-ycent); } define circle(xpix,ypix,xcent,ycent,rad) { return where(hypot(xpix-xcent, ypix-ycent) <= rad); } define ellipse(xpix,ypix,xcent,ycent,radx,rady,angl) { variable xtran, ytran; (xtran, ytran) = rotate(xpix,ypix,xcent,ycent,angl); variable rpix = (xtran/radx)^2+(ytran/rady)^2; return where(rpix <= 1); } define box(xpix,ypix,xcent,ycent,xlength,ylength,angl) { variable xtran, ytran; (xtran, ytran) = rotate(xpix,ypix,xcent,ycent,angl); return where( abs(xtran) <= xlength/2. and abs(ytran) <= ylength/2. ); } %%%%%%%%%%%%%%%%%%% define slsh_main () { % The binning of the lightcurve, in units of the multiple of the % basic time step between frames. variable tbin = 16; variable save_lightcurve = NULL; % The pileup levels at which we'll create the image variable pfrac = [0.01,0.02,0.05,0.1]; variable continuous_pfrac = 0; variable save_pileup_img = NULL; variable filename, outfile=NULL, filter_file=NULL; % energy bands (in keV) variable a_band, ea_lo=0.5, ea_hi=1.5, b_band, eb_lo=1.5, eb_hi=3., c_band, ec_lo=3., ec_hi=9.; % Usual pileup alpha parameter. variable alpha=qualifier("alpha",0.5); % Read in the user choices variable c = cmdopt_new (); c.add("nofilter", &nofilter; inc); c.add("tbin", &tbin; type="float"); c.add("save-lightcurve", &save_lightcurve; type="str"); c.add("pfrac", &pfrac; type="str"); c.add("cont-pfrac", &continuous_pfrac; inc); c.add("only-save-pileup-img", &save_pileup_img; type="str"); c.add("show-select", &show_select; inc); c.add("outfile", &outfile; type="str"); c.add("filter-file", &filter_file; type="str"); c.add("a-band", &a_band; type="str"); c.add("b-band", &b_band; type="str"); c.add("c-band", &c_band; type="str"); c.add("alpha", α type="float"); c.add("h|help", &exit_usage); c.add("v|version", &exit_version); variable i = c.process (__argv,1); if(i+1 != __argc) exit_usage(); filename = __argv[i]; if(outfile==NULL) outfile = filename; if(typeof(pfrac)==String_Type) pfrac = array_map(Double_Type, &atof, strtok(pfrac,"-([,;])")); if(typeof(a_band)==String_Type) a_band = array_map(Double_Type, &atof, strtok(a_band,"-([,;])")); if(typeof(b_band)==String_Type) b_band = array_map(Double_Type, &atof, strtok(b_band,"-([,;])")); if(typeof(c_band)==String_Type) c_band = array_map(Double_Type, &atof, strtok(c_band,"-([,;])")); % Some precautionary measures to make sure inputs are sane tbin = int(tbin); if( tbin < 1 ) tbin= 1; if(length(pfrac)<1) pfrac=[0.01]; pfrac = pfrac[array_sort(pfrac)]; ifnot(length(a_band)==2 and 0<__is_numeric(a_band)<3) a_band = [ea_lo, ea_hi]; ifnot(length(b_band)==2 and 0<__is_numeric(b_band)<3) b_band = [eb_lo, eb_hi]; ifnot(length(c_band)==2 and 0<__is_numeric(c_band)<3) c_band = [ec_lo, ec_hi]; ea_lo = min(a_band); ea_hi = max(a_band); eb_lo = min(b_band); eb_hi = max(b_band); ec_lo = min(c_band); ec_hi = max(c_band); % The base pileup level below which we set to the mean of non-zero pixels variable base = 3.e-3; if(base > pfrac[0]) base=pfrac[0]/2.; % event information (time, pha/pi value, x & y coordinates) variable evts = fits_read_table(filename, ["time","pi","x","y"]); % arrays for GTI times variable gti_lo, gti_hi; (gti_lo,gti_hi) = fits_read_col(filename+"[GTI]","start","stop"); % Total exposure time, frame time, integration time/frame, dead % time/frame, fractional exposure, start time, stop time variable expos, snapti, delay, tstart, tstop; (expos, snapti, delay, tstart, tstop) = fits_read_key(filename,"EXPOSURE","SNAPTI1","DELAY1","TSTART","TSTOP"); variable frame = snapti + delay; variable frac = snapti/frame; if(gti_lo[0] < tstart) gti_lo[0] = tstart; if(gti_hi[-1] > tstop) gti_hi[-1] = tstop; % We will first pre-filter the data & only keep the good times. variable gti_hist_bounds = Double_Type[2*length(gti_lo)]; gti_hist_bounds[[0::2]] = gti_lo; gti_hist_bounds[[1::2]] = gti_hi; variable rtot; variable gti_hist = histogram(evts.time, gti_hist_bounds, make_hi_grid(gti_hist_bounds), &rtot); variable gti_indx_array, gti_indx = Integer_Type[0]; foreach gti_indx_array (rtot[[0::2]]) gti_indx = [gti_indx,gti_indx_array]; struct_filter(evts, gti_indx); evts = struct_combine(evts, struct { kev = 3.65e-3*evts.pi }); % First create a lightcurve of rate in each frame. (We ignore any % slight misalignment of the histogram bins with the start/stop times % of each frame, and just work with the event times as being in the % middle of our bin. Final GTI filtering will take care of that, and % lose at most one frame on any GTI boundary.) variable lo = [tstart:tstop:frame]; variable hi = lo + frame; variable llo = length(lo); variable htot = histogram(evts.time, lo, hi, &rtot); % Exposure time in each frame - we will set to zero where there are % no counts. variable texp=Double_Type[llo]; texp[where(htot>0)] = frame*frac; % Need to add logic in case there are no good times variable rbin=Array_Type[llo/tbin+1]; $0 = Double_Type[llo/tbin+1]; variable texp_tot=@$0, bin_lo=@$0, bin_hi=@$0; ifnot(nofilter) { variable lightcurve = struct { time=@$0, rate=@$0, error=@$0, ra=@$0, rb=@$0, rc=@$0 }; variable ha = histogram(evts.time[where( ea_lo <= evts.kev < ea_hi )], lo, hi); variable hb = histogram(evts.time[where( eb_lo <= evts.kev < eb_hi )], lo, hi); variable hc = histogram(evts.time[where( ec_lo <= evts.kev < ec_hi )], lo, hi); } % Bin up the lightcurve by rates. Only include good time frames. _for i (0,llo-tbin,tbin) { variable j=i/tbin; variable indx = [i:min([i+tbin,llo])-1]; variable indx_indx, rbin_indx=Integer_Type[0]; foreach indx_indx (indx) rbin_indx = [rbin_indx,rtot[indx_indx]]; rbin[j] = rbin_indx; texp_tot[j] = sum(texp[indx]); bin_lo[j]=lo[indx[0]]; bin_hi[j]=hi[indx[-1]]; if(texp_tot[j]>0 and not nofilter) { lightcurve.rate[j] = sum(htot[indx]) /texp_tot[j]; lightcurve.error[j] = sqrt(sum(htot[indx]))/texp_tot[j]; lightcurve.ra[j] = sum(ha [indx]) /texp_tot[j]; lightcurve.rb[j] = sum(hb [indx]) /texp_tot[j]; lightcurve.rc[j] = sum(hc [indx]) /texp_tot[j]; } } variable igd = where(texp_tot>0); variable ivw = Integer_Type[0], iw; ifnot(nofilter) { lightcurve.time = (bin_lo + bin_hi)/2.; struct_filter(lightcurve, igd); if(filter_file != NULL) { lightcurve = struct_combine(lightcurve, struct{filter=Char_Type[length(lightcurve.time)]}); (gti_lo,gti_hi) = readcol(filter_file,1,2); _for i (0,length(gti_lo)-1,1) { iw = where( lightcurve.time >= gti_lo[i] and lightcurve.time <= gti_hi[i] ); if(length(iw)>0) lightcurve.filter[iw] = 1; } } lightcurve.time -= tstart; ivw = vwhere(lightcurve); lightcurve.time += tstart; if(filter_file == NULL) { lightcurve = struct_combine(lightcurve, struct{filter=Char_Type[length(lightcurve.time)]}); } if(ivw != NULL) { lightcurve.filter[*] = 0; lightcurve.filter[ivw] = 1; } if(save_lightcurve != NULL) fits_write_binary_table(save_lightcurve, "light curve", lightcurve, struct { TUNIT1 = "s", TUNIT2 = "c/s", TUNIT3 = "c/s", TUNIT4 = "c/s", TUNIT5 = "c/s", TUNIT6 = "c/s", TUNIT7 = "boolean", A_BAND = sprintf("%.3f-%.3f keV", ea_lo, ea_hi), B_BAND = sprintf("%.3f-%.3f keV", eb_lo, eb_hi), C_BAND = sprintf("%.3f-%.3f keV", ec_lo, ec_hi), TELESCOP = fits_read_key(filename, "TELESCOP"), INSTRUME = fits_read_key(filename, "INSTRUME"), OBJECT = fits_read_key(filename, "OBJECT"), MJDREFI = fits_read_key(filename, "MJDREFI"), MJDREFF = fits_read_key(filename, "MJDREFF"), }); } variable itm; if(length(ivw) > 0) { if(length(ivw)==length(igd)) ()=fprintf(stdout,"\nAll data selected; resulting filter is consistent with internal GTI.\n"); itm = igd[ivw]; } else { ()=fprintf(stdout,"\nNull vwhere filter; resulting filter is consistent with internal GTI.\n"); itm = igd; } % Take the selected points from vwhere, and figure out the % contiguous time intervals that they represent variable litm = length(itm); % Look for where there are gaps in the selected lightcurve. variable igap = where( (itm - shift(itm,-1)) > 1); if( length(igap) == 0 ) igap = [0,litm]; else igap = [0,igap, litm]; % Print out results in format suitable for xselect filtering ()=fprintf(stdout,"\nRequired Time Filter:\n\n"); variable fp = fopen(outfile+".flt","w"); _for i (1,length(igap)-1,1) { ()=fprintf(stdout,"%15.10e %15.10e\n", bin_lo[ itm[igap[i-1]] ], bin_hi[ itm[igap[i]-1] ]); ()=fprintf(fp ,"%15.10e %15.10e\n", bin_lo[ itm[igap[i-1]] ], bin_hi[ itm[igap[i]-1] ]); } ()=fclose(fp); ()=fprintf(stdout,"\n"); % Generate an array of indices of the events we have kept Need some % logic in case the choice results in a null selection variable lrev = array_map(Integer_Type,&length,rbin); itm = itm[where(lrev[itm] > 0)]; lrev = lrev[itm]; variable irev = int(cumsum([0,lrev])); variable ikeep = Integer_Type[int(sum(lrev))]; _for i (0,length(itm)-1,1) ikeep[[irev[i]:irev[i]+lrev[i]-1]] = rbin[itm[i]]; % The coordinates of what we just kept variable x = evts.x[ikeep]; variable y = evts.y[ikeep]; % Regrid to 1x1 pixel. variable dx = min(x)+0.5, dy=min(y)+0.5; variable xhist = [1:int(max(x)+dx):1]; variable yhist = [1:int(max(y)+dy):1]; variable piximg = histogram2d(y,x,yhist,xhist); variable lx = length(xhist), ly = length(yhist); variable xpix = Float_Type[ly,lx]; variable ypix = Float_Type[ly,lx]; _for i (0,ly-1,1) xpix[i,*] = xhist; _for i (0,lx-1,1) ypix[*,i] = yhist; % Smooth on 3x3, multiply by 9, divide by binning factors, to get % counts/3x3 pixels/frame piximg = (9.*conv3x3(piximg)/sum(texp_tot[itm]))*(frame*frac); % Convert to counts we *should* have seen without pileup. Third % order, alpha-dependent approximation piximg=(1+((2-alpha)/2.+(2*alpha^2-9*alpha+9)/6.*piximg)*piximg)*piximg; % Convert to pileup fraction - this is the "harshest" definition of % pileup fraction, f_t, from the Chandra ABC Guide. It is the % fraction of incident events affected by *either* grade *or* % energy migration. Other definitions of pileup fraction (of which % there are many) will give smaller numbers. piximg = 1 - exp(-piximg); variable pileimg=@piximg; ifnot(continuous_pfrac) { % Transform to discontinuous pileup fractions variable pmx = max(pileimg), npmx; i = where(pileimg < base and pileimg > 0); if(length(i)>0) { npmx = mean(pileimg[i]); pileimg[i] = npmx; } i = where(pileimg >= base and pileimg < pfrac[0]); if(length(i)>0) { pileimg[i] = base; npmx = base; } variable lpf = length(pfrac); _for j (1,lpf-1,1) { i = where(pileimg >= pfrac[j-1] and pileimg < pfrac[j]); if(length(i)>0) { pileimg[i] = pfrac[j-1]; npmx = pfrac[j-1]; } } i = where(pileimg >= pfrac[lpf-1]); if(length(i)>0) { pileimg[i] = pfrac[lpf-1]; npmx = pfrac[lpf-1]; } i = where(piximg >= npmx + (pmx-npmx)/2.); if(length(i)>0) pileimg[i] = pmx; } if(save_pileup_img != NULL) { fits_write_image_hdu(save_pileup_img, "estimated pileup fraction", pileimg, struct { CRPIX1 = fits_read_key(filename, "TCRPX10"), CDELT1 = fits_read_key(filename, "TCDLT10"), CTYPE1 = fits_read_key(filename, "TCTYP10"), CRVAL1 = fits_read_key(filename, "TCRVL10"), CUNIT1 = fits_read_key(filename, "TUNIT10"), CRPIX2 = fits_read_key(filename, "TCRPX11"), CDELT2 = fits_read_key(filename, "TCDLT11"), CTYPE2 = fits_read_key(filename, "TCTYP11"), CRVAL2 = fits_read_key(filename, "TCRVL11"), CUNIT2 = fits_read_key(filename, "TUNIT11"), }); exit(0); } % Open DS9 variable ds9 = open_ds9(); if(ds9==NULL) exit(1); % probably because of "Could not launch or contact ds9, giving up"... ds9.put_array(pileimg); % Let's apply a World Coordinate System ds9.set_wcs(struct { crpix = [1,1], crval = [1,1], cdelt = [1,1], ctype = ["linear","linear"], cunit = ["pixel","pixel"] }; alt='p', append); % Need to check how generic these keyword names are ds9.set_wcs(struct { crpix = [fits_read_key(filename,"TCRPX10","TCRPX11")], crval = [fits_read_key(filename,"TCRVL10","TCRVL11")], cdelt = [fits_read_key(filename,"TCDLT10","TCDLT11")], ctype = [fits_read_key(filename,"TCTYP10","TCTYP11")], cunit = ["deg","deg"] }); ds9.set_cmap("hsv"); % Make sure region formats and coordinate systems are the right ones ds9.send("regions system physical"); ds9.send("regions format ds9"); % Get the ds9 selected region and properly parse it variable dsreg=String_Type[1],ldsr=1; ()=fprintf(stdout,"\n Create include/exclude regions (circle, annulus, ellipse, box) using physical coordinates.\n"); variable reg_all = ["annulus","circle","ellipse","box"]; variable nreg_type = length(reg_all); variable phys_coord, reg_type, reg_add, reg_par; variable key = "n"; while(key != "q" and key != "y") { ()=fprintf(stdout,"\n Enter \'y\' when finished, or \'q\' to finish without a region file:\n"); key = getkey(); if(key=="y") { dsreg = ds9.get_regions(;system="physical",format="ds9"); ldsr = length(dsreg); phys_coord = Integer_Type[ldsr]; reg_type = Integer_Type[2*ldsr]; reg_add = Integer_Type[2*ldsr]; reg_par = Array_Type[2*ldsr]; % There better be at least two lines in the region file if(ldsr<2) { key="n"; ()=fprintf(stdout,"\n Hey! Could not parse region\n"); } else { _for i (0,ldsr-1,1) { % One line better say that these are physical coordinates phys_coord[i] = is_substr(dsreg[i],"physical"); % Check to see what kinds of regions are present, and % if they are include or exclude regions _for j (0,nreg_type-1,1) { if(is_substr(dsreg[i],reg_all[j])) { reg_type[i] = max([1,j]); reg_add[i] = 1; reg_par[i] = strtok(dsreg[i],"[(,)]"); % Turn the region string into just its parameters reg_par[i] = atof( reg_par[i][[1:length(reg_par[i])-1]] ); if(is_substr(dsreg[i],"-"+reg_all[j])) reg_add[i] = -1; % If annulus, break it up into its include and exclude regions if(j==0) { reg_type[i+ldsr] = reg_type[i]; reg_add[i+ldsr] = -1; reg_par[i+ldsr] = reg_par[i][[0:2]]; reg_par[i] = [ reg_par[i][[0:1]], reg_par[i][3] ]; } % If ellipse or box, check to see if it's an annulus % and if so, break it up into its include and exclude regions if(j>1 and length(reg_par[i])==7) { reg_type[i+ldsr] = reg_type[i]; reg_add[i+ldsr] = -1; reg_par[i+ldsr] = [ reg_par[i][[0:3]], reg_par[i][6] ]; reg_par[i] = [ reg_par[i][[0:1]], reg_par[i][[4:6]] ]; } } } } if(max(reg_add)<1) { key="n"; ()=fprintf(stdout,"\n Must be at least one include region\n"); } else if(max(reg_type)<1) { key="n"; ()=fprintf(stdout,"\n Could not parse region(s)\n"); } else if(max(phys_coord)<1) { key="n"; ()=fprintf(stdout,"\n File coordinates must be in physical coordinates.\n"); } else if(key!="q") { fp = fopen(outfile+".reg","w"); % We have to make sure the header comes first, plus % regions come next, then annulus regions, and minus % regions come last foreach j (where(reg_add[[0:ldsr-1]]==0)) ()=fprintf(fp,"%s\n",dsreg[j]); foreach j ( where(reg_add[[0:ldsr-1]]==1 and reg_add[[ldsr:2*ldsr-1]]!=-1) ) ()=fprintf(fp,"%s\n",dsreg[j]); foreach j ( where(reg_add[[0:ldsr-1]]==1 and reg_add[[ldsr:2*ldsr-1]]==-1) ) ()=fprintf(fp,"%s\n",dsreg[j]); foreach j (where(reg_add[[0:ldsr-1]]==-1)) ()=fprintf(fp,"%s\n",dsreg[j]); ()=fclose(fp); } } } } if(key=="q") { () = printf("\n"); return; } ikeep = Integer_Type[length(xpix)]; variable ireg; % Loop through the include regions foreach i (where(reg_add==1)) { switch(reg_type[i]) { case 1: ireg = circle(xpix,ypix,reg_par[i][0],reg_par[i][1],reg_par[i][2]); } { case 2: ireg = ellipse(xpix,ypix,reg_par[i][0],reg_par[i][1],reg_par[i][2], reg_par[i][3],reg_par[i][4]); } { case 3: ireg = box(xpix,ypix,reg_par[i][0],reg_par[i][1],reg_par[i][2], reg_par[i][3],reg_par[i][4]); } if(length(ireg) > 0) ikeep[ireg]=1; } % Loop through and then exclude the minus regions foreach i (where(reg_add==-1)) { switch(reg_type[i]) { case 1: ireg = circle(xpix,ypix,reg_par[i][0],reg_par[i][1],reg_par[i][2]); } { case 2: ireg = ellipse(xpix,ypix,reg_par[i][0],reg_par[i][1],reg_par[i][2], reg_par[i][3],reg_par[i][4]); } { case 3: ireg = box(xpix,ypix,reg_par[i][0],reg_par[i][1],reg_par[i][2], reg_par[i][3],reg_par[i][4]); } if(length(ireg) > 0) ikeep[ireg]=0; } % Estimate the pileup parameters for what's left, then save if(max(ikeep) > 0) { variable ilose = where(ikeep==0); ikeep = where(ikeep > 0); variable lm = sum(piximg[ikeep]); variable ls = sum(piximg[ikeep]^2); variable lc = sum(piximg[ikeep]^3); variable lavg = lm*lc^2/ls^3; variable fpsf = ls^2/lm/lc; variable neqv = ls^3/lc^2/9; if(length(ilose) > 0 and show_select) { pileimg[ilose] = 0.; ds9.put_array(pileimg); } variable text = "\n" +sprintf("Suggested pileup model parameters for %s,\n", filename) +sprintf("using region file %s.reg and filter file %s.flt:\n", outfile, outfile) + "\n" +sprintf(" Frame Time (set_frame_time) : %6.4f\n", snapti) +sprintf(" Effective piled PSF fraction : %6.4f\n", fpsf) +sprintf(" Equivalent number of regions : %6i\n", int(neqv)) +sprintf(" Max equivalent pileup fraction: %6.4f * %6.4f = %6.4f\n", lavg, fpsf, lavg*fpsf) + "\n"; ()=fprintf(stdout, text); fp = fopen(outfile+".parms","w"); ()=fprintf(fp, text); ()=fclose(fp); } else ()=printf("Empty region.\n\n"); }