; docformat = 'rst' ;+ ; This function finds the best-fitting Choloniewski function for ; input arrays of absolute magnitudes, surface brightness, phi ; and phi_err. ;- ;+ ; Estimate phierr for bins with zero phierr ;- PRO ajs_choloniewski_fit_phierr, absmag, sb, phi, phierr, $ vars=vars, zmin=zmin, zmax=zmax, area=area, $ q0=q0, q1=q1 compile_opt idl2 debug = ajs_debug() IF debug GE 1 THEN BEGIN message, 'Estimating phierr for bins with zero phierr', /inf message, ajs_kw_string(zmin=zmin, zmax=zmax, area=area, q0=q0, q1=q1), $ /inf ENDIF IF n_elements(vars) EQ 0 $ OR n_elements(zmin) EQ 0 $ OR n_elements(zmax) EQ 0 $ OR n_elements(area) EQ 0 THEN $ message, 'Zero phierr: supply vars, zmin, zmax and area' $ ELSE BEGIN IF debug GE 2 THEN print, alog10(phierr), format='(' $ + strtrim(n_elements(absmag), 2) + 'I2)' ;; Multiplier: phierr = 1. / vmax * err_multip ;; Taking into account the number of degrees of freedom ;; so that 1-sigma errors (chi^2) will give phierr (why? fudge again??) ;; See ajs_bbd_plot k = n_elements(phierr) chi2_bin = sqrt(2. / k) err_multip = 1. / sqrt(chi2_bin) ;; Scale according to bin widths (larger error for smaller bins) err_multip = err_multip / abs(absmag[1] - absmag[0]) / abs(sb[1] - sb[0]) err_multip *= 10 ; fudge IF debug GE 2 THEN $ message, 'Errors multiplied by ' + strtrim(err_multip, 2), /inf ;; Which bins need attention? zeros = where(phierr LE 0) ;; How many extra variables are we dealing with? n_other_vars = n_elements(vars) - 2 ;; Default coeffs (see ajs_dm_k.pro) coeffs = [1.89821e-05, 2.37252e-09, 1.97939e-06, 7.54209e-08, $ 1.93300e-08] ;; Create structure for table table = create_struct('coeffs', fltarr(5)) FOR i = 0, n_elements(vars) - 1 DO BEGIN table = create_struct(vars[i].abs_name, 0.0, table) ENDFOR IF n_other_vars EQ -1 THEN BEGIN ;; Consider only absmag IF debug GE 2 THEN message, 'Using only absmag', /inf coeffs = coeffs # (intarr(n_elements(zeros)) + 1) ;; Create table of galaxies at centre of each zero bin table = replicate(table, n_elements(zeros)) ;; Assign data to table table.coeffs = coeffs table.(where(tag_names(table) EQ strupcase(vars[0].abs_name))) $ = absmag[reform((array_indices(phi, zeros))[0, *])] ;; Find vmax and set error = 1. / vmax vmax = ajs_vmax(table, vars, zmin=zmin, zmax=zmax, area=area, $ q0=q0, q1=q1) phierr[zeros] = 1. / vmax * err_multip ENDIF ELSE IF n_other_vars EQ 0 THEN BEGIN ;; Consider only absmag and sb IF debug GE 2 THEN message, 'Using only absmag & sb', /inf coeffs = coeffs # (intarr(n_elements(zeros)) + 1) ;; Create table of galaxies at centre of each zero bin table = replicate(table, n_elements(zeros)) ;; Assign data to table table.coeffs = coeffs table.(where(tag_names(table) EQ strupcase(vars[0].abs_name))) $ = absmag[reform((array_indices(phi, zeros))[0, *])] table.(where(tag_names(table) EQ strupcase(vars[1].abs_name))) $ = sb[reform((array_indices(phi, zeros))[1, *])] ;; Find vmax and set error = 1. / vmax vmax = ajs_vmax(table, vars, zmin=zmin, zmax=zmax, area=area, $ q0=q0, q1=q1) phierr[zeros] = 1. / vmax * err_multip ENDIF ELSE BEGIN ;; Consider other variables apart from absmag and sb IF debug GE 2 THEN message, 'Using absmag, sb and ' $ + strtrim(n_other_vars, 2) $ + ' other variables', /inf ;; Create table of galaxies at centre of each bin (zero or nonzero) nbins = 10 table = replicate(table, n_elements(absmag) * n_elements(sb) $ * nbins ^ n_other_vars) ;; Assign data to table table.coeffs = rebin(coeffs, 5, n_elements(table)) ;; Dimensions of n-d space of bin centres dims = [n_elements(absmag), n_elements(sb), $ intarr(n_other_vars) + nbins] ;; Bin centres for other variables var_arr = fltarr(n_other_vars, nbins) FOR i = 0, n_other_vars - 1 DO BEGIN var_arr[i, *] = ajs_linspace(vars[i].abs_min, vars[i].abs_max, $ nbins) ENDFOR ;; Assign values to table FOR j = 0, n_elements(vars) - 1 DO BEGIN CASE j OF 0: arr_tmp = absmag 1: arr_tmp = sb ELSE: arr_tmp = var_arr[j - 2: *] ENDCASE table.(where( $ tag_names(table) EQ strupcase(vars[j].abs_name))) $ = reform(arr_tmp[(array_indices( $ dims, lindgen(n_elements(table)), $ /dimensions))[j, *]]) ENDFOR IF debug GE 2 THEN message, 'Done assigning table values', /inf ;; Find vmax and set error = 1. / vmax vmax = ajs_vmax(table, vars, zmin=zmin, zmax=zmax, area=area, $ q0=q0, q1=q1) vmax = reform(vmax, dims) FOR i = 0, n_other_vars - 1 DO BEGIN ;; Find maximum over one dimension vmax = max(vmax, dimension=3) ENDFOR phierr[zeros] = 1. / vmax[zeros] * err_multip ENDELSE IF debug GE 2 THEN print, alog10(phierr), format='(' $ + strtrim(n_elements(absmag), 2) + 'I2)' ENDELSE END ;+ ; This function finds the best-fitting Choloniewski function for ; input arrays of absolute magnitudes, surface brightness, phi ; and phi_err. ; :Returns: ; Choloniewski parameters [mstar,alpha,phistar,sbstar,sigmasb,beta] ; :Params: ; absmag : in, required ; [n1] Bin centres for absolute magnitude ; sb : in, required ; [n2] Bin centres for surface brightness ; phi : in, required ; [n1, n2] Value of space density at absmag and sb ; phierr : in, out, required ; [n1, n2] If any values of phierr are zero, either raises an error ; message or estimates (and changes input) values using vars etc. ; params_init : in, optional ; Initial guess for ; [mstar,alpha,phistar,sbstar,sigmasb,beta] (or default) ; :Keywords: ; txtfile : in, optional ; Output text file for Choloniewski parameters ; xrange : in, optional, type=fltarr(2) ; Range in m1 for fitting ; yrange : in, optional, type=fltarr(2) ; Range in m2 for fitting ; vars : in, optional ; For estimating errors on bins with zero phi or phierr, for Choloniewski ; fit. Array of structures with fields {abs_name:} giving the column ; name in table corresponding to the absolute value, {band:} giving the ; name of the band, {type:} giving 'M'agnitudes, 'S'urface brightness ; or 'R'adius and {app_min:, app_max: abs_min: abs_max:} giving the ; limits. The array must be ordered so that vars[0] corresponds ; to absmag and vars[1] corresponds to sb. ; zmin : in, optional ; Minimum redshift. Use with vars when performing Choloniewski ; fit with phi = 0 and phierr = 0 in some bins ; zmax : in, optional ; Maximum redshift. Use with vars when performing Choloniewski ; fit with phi = 0 and phierr = 0 in some bins ; area : in, optional ; Area in square degrees. Use with vars when performing Choloniewski ; fit with phi = 0 and phierr = 0 in some bins ; q0 : in, optional ; Evolution parameters: for ajs_vmax ; q1 : in, optional ; Evolution parameters: for ajs_vmax ; cov_mat : out, optional ; Covariance matrix ; _REF_EXTRA : in, optional ; Extra keywords to pass to mpfit2dfun ; :Uses: ; mpfit2d (idlutils) ; ajs_choloniewski ; :History: ; 17 Jan 2008 Created, Anthony Smith ; ; 4 Apr 2008 Added xrange and yrange ;- FUNCTION ajs_choloniewski_fit, absmag, sb, phi, phierr, params_init, $ txtfile=txtfile, xrange=xrange, yrange=yrange, $ vars=vars, zmin=zmin, $ zmax=zmax, area=area, q0=q0, q1=q1, $ cov_mat=cov_mat, _REF_EXTRA=e compile_opt idl2 debug = ajs_debug() IF debug GE 1 THEN message, 'Choloniewski fit', /inf IF n_elements(params_init) EQ 0 THEN $ params_init=[median(absmag), -1, 0.01, $ median(sb), 1, 1] params_init = double(params_init) ;; Bins with zero phierr: estimate phierr from Vmax nans = where(finite(phierr, /nan), n_nans) IF n_nans GT 0 THEN $ phierr[nans] = 0 IF min(phierr) LE 0 THEN BEGIN ajs_choloniewski_fit_phierr, absmag, sb, $ phi, phierr, $ vars=vars, zmin=zmin, zmax=zmax, $ area=area, $ q0=q0, q1=q1 ENDIF ;; Check xrange & yrange are [min, max] not [max, min] IF n_elements(xrange) GT 1 THEN $ IF xrange[0] GT xrange[1] THEN $ xrange = reverse(xrange) IF n_elements(yrange) GT 1 THEN $ IF yrange[0] GT yrange[1] THEN $ yrange = reverse(yrange) ;; Restrict fit to bins within xrange and yrange IF n_elements(xrange) GT 1 THEN $ fitx = where(absmag GE xrange[0] AND absmag LE xrange[1]) $ ELSE $ fitx = indgen(n_elements(absmag)) IF n_elements(yrange) GT 1 THEN $ fity = where(sb GE yrange[0] AND sb LE yrange[1]) $ ELSE $ fity = indgen(n_elements(sb)) absmag_fit = absmag[fitx] sb_fit = sb[fity] phi_fit = (phi[fitx, *])[*, fity] phierr_fit = (phierr[fitx, *])[*, fity] ;; Make 2d arrays from 1d inputs: Array[n_elements(absmag), n_elements(sb)] absmag_arr = absmag_fit # (sb_fit * 0 + 1) sb_arr = (absmag_fit * 0 + 1) # sb_fit params=mpfit2dfun('ajs_choloniewski', $ absmag_arr, $ sb_arr, $ phi_fit, $ phierr_fit, $ params_init, /quiet, covar=cov_mat, perror=perror, $ _STRICT_EXTRA=e) IF keyword_set(txtfile) THEN BEGIN ;; Text file openw, unit, txtfile, /get_lun printf, unit, params free_lun, unit ENDIF RETURN, params END ;+ ; Test ajs_choloniewski_fit ;- PRO ajs_choloniewski_fit_test compile_opt idl2 params_true = [-23.5, -1, 0.01, 17, 1, 0.5] n_mag = 32 n_sb = 24 m = ajs_linspace(-20, -26, n_mag, /bincentres) sb = ajs_linspace(20, 14, n_sb, /bincentres) chol = ajs_choloniewski(m, sb, params_true) cholerr = chol / 10 IF 1 THEN BEGIN ;; Simulate magnitude-limited sample ;; Table, with one galaxy at each abs_mag coeffs = [1.89821e-05, 2.37252e-09, 1.97939e-06, 7.54209e-08, $ 1.93300e-08] table = replicate(create_struct('coeffs', coeffs, 'absmag', 0.0), n_mag) table.absmag = m ;; Limits vars = [{abs_name:'absmag', band:'K', type:'M', app_min:12, app_max:16}] ;; Calculate Vmax vmax = ajs_vmax(table, vars, zmin=0.01, zmax=0.3, area=500) vmax_bbd = rebin(vmax, n_mag, n_sb) ;; Number of galaxies at each value of absmag & sb n_gals = chol * vmax_bbd cholerr = sqrt(chol / vmax_bbd) ; = chol / sqrt(n_gals) min_n = 100 IF min(n_gals) LT min_n THEN BEGIN chol[where(n_gals LT min_n)] = 0 cholerr[where(n_gals LT min_n)] = 1000. / vmax_bbd[where(n_gals $ LT min_n)] ENDIF ENDIF ;; Fit ; params_init = params_true * 1.1 params = ajs_choloniewski_fit(m, sb, chol, cholerr, cov_mat=cov_mat) ;, params_init) perror = sqrt(diag_matrix(cov_mat)) print,'True/Fitted parameters, +/- error:' print, transpose([[params_true], [params], [perror]]) window, 0 ajs_bbd_plot, m, sb, chol, phibbderr=cholerr, choloniewski=params, band='K' ;; Adjust errors to give 1-sigma in chi^2 k = n_elements(cholerr) chi2_bin = sqrt(2. / k) cholerr_chi2 = sqrt(chi2_bin) * cholerr window, 1 ajs_bbd_plot, m, sb, chol + cholerr_chi2, choloniewski=params, band='K' window, 2 ajs_bbd_plot, m, sb, chol - cholerr_chi2, choloniewski=params, band='K' END