ProFound/ProFit: A Complex Fit

Aaron Robotham

2017-12-07

Load some libraries:

library(ProFound)
## Loading required package: magicaxis
## Loading required package: MASS
## Loading required package: plotrix
## Loading required package: sm
## Package 'sm', version 2.2-5.4: type help(sm) for summary information
## 
## Attaching package: 'sm'
## The following object is masked from 'package:MASS':
## 
##     muscle
## Loading required package: mapproj
## Loading required package: maps
## Loading required package: celestial
## Loading required package: RANN
## Loading required package: NISTunits
## Loading required package: pracma
## 
## Attaching package: 'pracma'
## The following object is masked from 'package:sm':
## 
##     nile
## Loading required package: FITSio
## Loading required package: data.table
library(ProFit)
## Loading required package: Rcpp
## Warning: package 'Rcpp' was built under R version 3.4.2
image=readFITS(system.file("extdata", 'VIKING/mystery_VIKING_Z.fits', package="ProFound"))
profound=profoundProFound(image, magzero=30, verbose=TRUE, plot=TRUE, boundstats=TRUE, rotstats=TRUE)
## Running ProFound:
## Supplied image contains image and header components
## Supplied image is 356 x 356 pixels
## Extracted pixel scale from header provided: 0.339 asec/pixel
## Supplied image is 2.011 x 2.011 amin,  0.001 deg-sq
## Making initial sky map - 0.001 sec
##  - Sky statistics :
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -2.3257 -0.1157  0.5354  0.5499  1.0154  4.0443
##  - Sky-RMS statistics :
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   8.318   8.915   9.122   9.121   9.273   9.882
## Making initial segmentation image - 0.569 sec
##  - Running MakeSegim:
##  - Skipping making initial local estimate of the sky - User provided sky
##  - Skipping making initial local estimate of the sky RMS - User provided sky RMS
##  - Smoothing the image - 0.325 sec
##  - Watershed de-blending - 0.328 sec
##  - Skipping segmentation plot - plot set to FALSE
##  - Skipping making final local estimate of the sky - User provided sky
##  - Skipping making initial local estimate of the sky RMS - User provided sky RMS
##  - Skipping segmentation statistics - segstats set to FALSE or no segments
##  - MakeSegim is finished! - 0.344 sec
## Doing initial aggressive dilation - 0.915 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Skipping segmentation statistics - segstats set to FALSE
##  - profoundMakeSegimDilate is finished! - 0.022 sec
## Making better sky map - 0.939 sec
##  - Sky statistics :
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## -2.32792 -0.73111 -0.42721 -0.45022 -0.03966  0.41956
##  - Sky-RMS statistics :
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   8.317   8.697   8.799   8.822   8.982   9.199
## Calculating initial segstats - 1.154 sec
## Doing dilations:
## Iteration 1 of 6 - 1.23 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Calculating segstats - 0.067 sec
##  - profoundMakeSegimDilate is finished! - 0.268 sec
## Iteration 2 of 6 - 1.533 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0 sec
##  - Calculating segstats - 0.015 sec
##  - profoundMakeSegimDilate is finished! - 0.043 sec
## Iteration 3 of 6 - 1.579 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Calculating segstats - 0.009 sec
##  - profoundMakeSegimDilate is finished! - 0.044 sec
## Iteration 4 of 6 - 1.624 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Calculating segstats - 0.018 sec
##  - profoundMakeSegimDilate is finished! - 0.052 sec
## Iteration 5 of 6 - 1.678 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Calculating segstats - 0.07 sec
##  - profoundMakeSegimDilate is finished! - 0.107 sec
## Iteration 6 of 6 - 1.786 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Calculating segstats - 0.015 sec
##  - profoundMakeSegimDilate is finished! - 0.057 sec
## Finding CoG convergence - 1.843 sec
## Constructing final segim - 1.845 sec
## Doing final aggressive dilation - 1.881 sec
##  - Running MakeSegimDilate:
##  - Dilating segments - 0.001 sec
##  - Skipping segmentation statistics - segstats set to FALSE
##  - profoundMakeSegimDilate is finished! - 0.02 sec
## Making final sky map - 1.902 sec
##  - Sky statistics :
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -2.3270 -0.7348 -0.5039 -0.4977 -0.1780  0.5313
##  - Sky-RMS statistics :
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   8.324   8.660   8.779   8.798   8.969   9.195
## Calculating final segstats for 86 objects - 2.083 sec
##  - magzero = 30
##  - gain = NULL (ignored)
##  - pixscale = 0.339
##  - rotstats = TRUE
##  - boundstats = TRUE
## Plotting segments - 2.854 sec
## ProFound is finished! - 3.967 sec

We can identify the large group of central potentially confused sources from the group output from ProFound:

profound$group$groupsegID[1,]
##   groupID                     segID Ngroup
## 1       1 1, 2, 3, 5, 6, 14, 56, 57      8

The main group has 8 segments, which we can view easily:

magimage(profound$group$groupim==1)

We can check the properties of the group 1 segments too:

group1segstats=profound$segstats[profound$segstats$segID %in% unlist(profound$group$groupsegID[1,"segID"]),]
group1segstats
##    segID uniqueID     xcen      ycen  xmax  ymax    RAcen    Deccen
## 1      1   222149 220.7910 148.79252 221.5 148.5 352.2866 -31.82505
## 2      2   227142 226.5476 140.89381 226.5 141.5 352.2860 -31.82579
## 3      3   194148 194.5818 147.24543 193.5 147.5 352.2895 -31.82519
## 5      5   175133 174.8384 132.82411 174.5 132.5 352.2917 -31.82655
## 6      6   178179 177.0329 179.32914 177.5 178.5 352.2915 -31.82217
## 14    14   165108 165.7946 108.83922 164.5 107.5 352.2927 -31.82881
## 56    56   180100 182.1247  96.24151 179.5  99.5 352.2909 -31.83000
## 57    57   155117 153.1687 116.03722 154.5 116.5 352.2941 -31.82813
##       RAmax    Decmax       sep         flux      mag     cenfrac
## 1  352.2866 -31.82508 0.2599896 2790717.0145 13.88571 0.033702410
## 2  352.2860 -31.82574 0.2061311 1175345.4900 14.82459 0.028589705
## 3  352.2897 -31.82517 0.3767554   71955.9488 17.85733 0.024069923
## 5  352.2918 -31.82658 0.1588496   30310.6565 18.79601 0.008326382
## 6  352.2914 -31.82225 0.3226193   42012.7303 18.44155 0.005392862
## 14 352.2929 -31.82894 0.6314326    7407.4903 20.32582 0.012864780
## 56 352.2912 -31.82969 1.4184049    1109.7772 22.38691 0.026837741
## 57 352.2940 -31.82809 0.4777916     559.6111 23.13028 0.061579882
##          N50       N90 N100       R50      R90      R100   SB_N50   SB_N90
## 1   25.53866 125.76701 1177 1.0381943 2.303897  7.048031 15.80728 16.90002
## 2   31.65729 156.36020 1301 1.2019195 2.671171  7.705081 16.97934 18.07529
## 3   54.09739 546.88782 1084 1.8586611 5.909642  8.320065 20.59385 22.46747
## 5  118.82350 438.75100  773 2.8186292 5.416214  7.189133 22.38684 23.16695
## 6  162.36038 539.21549 1002 4.3075739 7.850076 10.701054 22.37132 23.03635
## 14  75.40545 229.20005  543 1.8251468 3.182026  4.897747 23.42290 23.99175
## 56  29.69214  64.22222  384 1.1204833 1.647887  4.029492 24.47209 24.67152
## 57  11.05394  29.45675   63 0.8059346 1.315629  1.924028 24.14265 24.56864
##     SB_N100      xsd      ysd       covxy      corxy       con     asymm
## 1  19.21365 3.263228 3.219536   1.4857455  0.1414177 0.4506254 0.2143580
## 2  20.26128 3.934452 3.695753   3.0363155  0.2088141 0.4499598 0.2923601
## 3  23.09590 4.674415 8.042726  -4.5131667 -0.1200469 0.3145133 0.3351690
## 5  23.66746 6.225887 5.858164 -19.5785947 -0.5368077 0.5204058 0.1439220
## 6  23.59472 8.538110 8.381656 -58.2572767 -0.8140641 0.5487302 0.1948959
## 14 24.81382 5.322456 4.933950   4.4887259  0.1709292 0.5735800 0.2442067
## 56 26.49874 5.253762 5.506135   3.9390976  0.1361694 0.6799517 0.3634085
## 57 25.27963 1.587067 2.326818   0.9845412  0.2666098 0.6125849 0.3343005
##    flux_reflect mag_reflect   semimaj  semimin     axrat        ang
## 1  3798317.9926    13.55102  3.464032 3.002425 0.8667429 132.277466
## 2  2245080.6965    14.12192  4.211792 3.376286 0.8016271 126.652402
## 3   116152.1823    17.33743  8.071914 4.623830 0.5728295   5.949694
## 5    34775.7533    18.64681  7.499609 4.103123 0.5471116  48.237135
## 6    43419.3543    18.40579 11.395089 3.647387 0.3200841  45.650757
## 14    8677.4590    20.15402  5.589921 4.628735 0.8280502 123.032897
## 56    1184.1007    22.31653  5.755545 4.979281 0.8651275 144.509207
## 57     509.2958    23.23257  2.391056 1.488528 0.6225399 162.890257
##      signif    FPlim  flux_err      mag_err flux_err_sky flux_err_skyRMS
## 1       Inf 2.353971 336.79366 0.0001310305   150.953395       301.06983
## 2       Inf 2.316502 367.08866 0.0003391015   188.692738       314.87956
## 3       Inf 2.384412 306.25938 0.0046211175   104.049566       288.04252
## 5       Inf 2.506347 259.50745 0.0092956296    92.226481       242.56627
## 6       Inf 2.413217 298.55100 0.0077154622   102.896518       280.25882
## 14      Inf 2.628787 206.21958 0.0302261707    39.475644       202.40600
## 56 1.160750 2.744526 171.16109 0.1674532383    19.492366       170.04754
## 57 5.795389 3.292165  69.01839 0.1339068419     1.394704        69.00429
##    flux_err_shot    sky_mean    sky_sum skyRMS_mean Nedge Nsky Nobject
## 1              0 -0.05442729  -64.06092    8.775595   181  103      78
## 2              0  0.17785361  231.38754    8.729826   187  141      46
## 3              0 -0.29206174 -316.59492    8.748622   183   57     126
## 5              0 -0.51450016 -397.70862    8.724495   114   63      51
## 6              0 -0.60529210 -606.50268    8.853633   138  108      30
## 14             0 -0.52316357 -284.07782    8.686067    82   56      26
## 56             0 -0.31370073 -120.46108    8.677698    69   59      10
## 57             0 -0.69329652  -43.67768    8.693723    25   17       8
##    Nborder Nmask edge_frac edge_excess flag_border iter  origfrac
## 1        0     0 0.5690608   1.4825964           0    0 1.0000000
## 2        0     0 0.7540107   1.4492189           0    0 1.0000000
## 3        0     0 0.3114754   1.4815620           0    1 0.9819151
## 5        0     0 0.5526316   1.0826823           0    1 0.9611582
## 6        0     0 0.7826087   0.9874888           0    1 0.9621054
## 14       0     0 0.6829268   0.9860958           0    3 0.8045199
## 56       0     0 0.8550725   0.9894014           0    6 0.1259890
## 57       0     0 0.6800000   0.8525633           0    1 0.5556939
##    flag_keep
## 1       TRUE
## 2       TRUE
## 3       TRUE
## 5       TRUE
## 6       TRUE
## 14      TRUE
## 56     FALSE
## 57      TRUE

In our Full Monty vignette example we detail how to extract a reasonable PSF. We use the solution here.

psf_modellist=list(
  moffat=list(
    xcen=75/2,
    ycen=75/2,
    mag=0,
    fwhm=3.8,
    con=2.04,
    ang=0,
    axrat=1,
    box=0
  )
)
psf_model=profitMakeModel(modellist=psf_modellist, dim=c(75,75))$z

We can see where this FWHM lies in comparison to the values estimated from ProFound.

maghist(profound$segstats$R50*2/0.339,breaks=20)
## [1] "Summary of used sample:"
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.368   4.371   5.530   6.154   7.144  25.413 
## [1] "sd / 1-sig / 2-sig range:"
## [1] 3.099771 1.803710 4.376488
## [1] "Plotting 86 out of 86 (100%) data points (0 < xlo & 0 > xhi)"
abline(v=4.47, lty=2)

Have a quick check:

magimage(psf_model)

Let’s try fitting all the sources as Sersic profiles!

group1_modellist=list(
  pointsource=list(
    xcen= group1segstats$xmax[1:3],
    ycen= group1segstats$ymax[1:3],
    mag= group1segstats$mag[1:3]
  ),
  sersic=list(
    xcen= group1segstats$xmax[4:5],
    ycen= group1segstats$ymax[4:5],
    mag= group1segstats$mag[4:5],
    re= group1segstats$R50[4:5]/0.339,
    nser= rep(1, 2),
    ang= group1segstats$ang[4:5],
    axrat= group1segstats$axrat[4:5],
    box= rep(0, 2)
  )
)

group1_interval=list(
  pointsource=list(
    xcen= rep(list(c(-1,1)),3),
    ycen= rep(list(c(-1,1)),3),
    mag= rep(list(c(-2,2)),3)
  ),
  sersic=list(
    xcen= rep(list(c(-1,1)),2),
    ycen= rep(list(c(-1,1)),2),
    mag= rep(list(c(-2,2)),2),
    re= rep(list(c(0.5,2)),2),
    nser= rep(list(c(0.5,10)),2),
    ang= rep(list(c(-180,360)),2),
    axrat= rep(list(c(0.1,1)),2),
    box= rep(list(c(-1,1)),2)
  )
)
for(i in 1:3){
  group1_interval$pointsource$xcen[[i]]=group1_modellist$pointsource$xcen[i]+group1_interval$pointsource$xcen[[i]]
  group1_interval$pointsource$ycen[[i]]=group1_modellist$pointsource$ycen[i]+group1_interval$pointsource$ycen[[i]]
  group1_interval$pointsource$mag[[i]]=group1_modellist$pointsource$mag[i]+group1_interval$pointsource$mag[[i]]
}
for(i in 1:2){
  group1_interval$sersic$xcen[[i]]=group1_modellist$sersic$xcen[i]+group1_interval$sersic$xcen[[i]]
  group1_interval$sersic$ycen[[i]]=group1_modellist$sersic$ycen[i]+group1_interval$sersic$ycen[[i]]
  group1_interval$sersic$mag[[i]]=group1_modellist$sersic$mag[i]+group1_interval$sersic$mag[[i]]
  group1_interval$sersic$re[[i]]=group1_modellist$sersic$re[i]*group1_interval$sersic$re[[i]]
}

group1_tofit=list(
  pointsource=list(
    xcen= rep(TRUE, 3),
    ycen= rep(TRUE, 3),
    mag= rep(TRUE, 3)
  ),
  sersic=list(
    xcen= rep(TRUE, 2),
    ycen= rep(TRUE, 2),
    mag= rep(TRUE, 2),
    re= rep(TRUE, 2),
    nser= rep(TRUE, 2),
    ang= rep(TRUE, 2),
    axrat= rep(TRUE, 2),
    box= rep(FALSE, 2)
  )
)

group1_tolog=list(
  pointsource=list(
    xcen= rep(FALSE, 3),
    ycen= rep(FALSE, 3),
    mag= rep(FALSE, 3)
  ),
  sersic=list(
    xcen= rep(FALSE, 2),
    ycen= rep(FALSE, 2),
    mag= rep(FALSE, 2),
    re= rep(TRUE, 2),
    nser= rep(TRUE, 2),
    ang= rep(FALSE, 2),
    axrat= rep(TRUE, 2),
    box= rep(FALSE, 2)
  )
)
sigma=profoundMakeSigma(image$imDat, objects=profound$objects, gain=0.5, sky=profound$sky, skyRMS =profound$skyRMS, plot=TRUE)

group1_Data=profitSetupData(image$imDat-profound$sky, sigma=sigma, modellist=group1_modellist, tofit=group1_tofit, tolog=group1_tolog, intervals=group1_interval, magzero=30, algo.func='optim', psf=psf_model, region=matrix(profound$segim %in% unlist(profound$group$groupsegID[1,'segID'])[1:5], 356), verbose=FALSE)
profitLikeModel(parm=group1_Data$init, Data=group1_Data, makeplots=TRUE, plotchisq=TRUE)

Next we will run a simple optimisation scheme (because we do not have all day…)

group1_fit=optim(group1_Data$init, profitLikeModel, method='BFGS', Data=group1_Data, control=list(fnscale=-1))

And check the results!

profitLikeModel(parm=group1_fit$par, Data=group1_Data, makeplots=TRUE, plotchisq=TRUE)

That is looking pretty pretty pretty good. A bit of residual structure in the central part, but that is as we might expect seeing as we did not attempt to create a more complex (e.g. elliptical and boxy) PSF.

We can compare the inputs and outputs easily too:

group1_modellist_fit=profitRemakeModellist(parm=group1_fit$par, Data=group1_Data)$modellist
group1_modellist_fit

We can also see the change in a nicely formatted way if we use the relist function in R:

relist(unlist(group1_modellist)-unlist(group1_modellist_fit), skeleton = group1_modellist)

The stars have migrated position a small amount, as have the extended sources. The extended sources have both hit a position limit, so it might be sensible to expand the allowed x and y centre intervals. Other parameters are barely changed, e.g. the initial ProFound guesses for the Re (re) and angle (ang) are actually very good. The axial ratios for the extended sources has changed a bit, but this should be expected since these are highly elliptical sources and the convolution with the PSF will be puffing them out when measured without accounting for the PSF in ProFound.

The two bright PSF magnitudes have changed the most, which is not surprising since they were blended together. It is notable that the raw magnitudes calculated by ProFound are actually nearer to the fit values than the rotstats variants. In practice, there is rarely an occasion where the raw segmented magnitudes are not a good enough a starting point for optimisation in ProFit, since it is in practice hard for them to be more than a factor two wrong in flux, which is easily accurate enough for a sensible starting point with ProFit.