-
Notifications
You must be signed in to change notification settings - Fork 10
Best practice for book keeping? #196
Description
Once again let me say that i am blown away by the power of this wonderful tool. So much fun.
I am currently working to build an image calibration pipeline, centred on astrophot modelling/photometry for stars. There are a few steps to the process: first i fit many stars separately and independent to assess their suitability for PSF modelling; then i fit an ensemble of 'good' stars with a single model to determine the PSF and to get the positions and fluxes to be used for astrometric and photometric calibration. Like i say: fun! : )
The hardest part of this with astrophot is actually tracking and extracting the results of the fits — which says a lot about how good astrophot is at what it is supposed to do! But still, it would be good to have some documentation or guidance and possibly even some extra functionality to help with record keeping.
I'm not sure that what i'm doing is particularly good or clever, but just to show the approach that i have gravitated towards:
In the first phase when i fit many stars separately and independently, here is what i do:
list_of_row_data = []
for star in stars :
# relevant information for this source
objid, xcen, ycen = star['objid'], star['xcen'], star['ycen']
# create the model for this source
star_model = astrophot.models.AstroPhot_Model(
name=str(star['pts_key']), target=target_image, pixelscale=1,
model_type='point model', parameters={"center":[xcen, ycen], "flux":1.7},
psf=psf_model, psf_mode='full' )
# do the fit
star_result = astrophot.fit.LM( star_model ).fit()
star_result.update_uncertainty()
# now start extracting values
star_values = star_model.parameters.vector_values().detach().cpu().numpy()
star_covar = star_result.covariance_matrix.detach().cpu().numpy()
star_chi2min = star_result.chi2min()
# assemble these into what will become a table row - this is brittle
row_data = np.hstack(( star['pts_key'], # identifier
star_values, # fit parameters (n, Rd, x, y, flux)
np.sqrt(np.diag(star_covar)), # fit uncertainties
star_chi2min # min chi2
))
# append this row array to a list
list_of_row_data.append( row_data )
# define the column names corresponding to the row data - this is brittle
colnames = ( 'pts_key star_shape star_size star_xcenter star_ycenter star_logflux'
' star_shape_unc star_size_unc star_xcenter_unc star_ycenter_unc star_logflux_unc'
' star_chi2_min'
).split()
# then construct the final output as an astropy Table
data = Table( { col : vals for (col, vals)
in zip(colnames, np.vstack(list_of_row_data).T) } )
In the later phase, when i have the positions and fluxes of many stars fit with the same PSF, i have a different but equally awkward pattern:
model = astrophot.models.AstroPhot_Model(
name='psf star models', target=target_image,
model_type='group model', psf_mode='full',
models=good_star_models, # this is a list of point source models
)
model.initialize()
result = astrophot.fit.LM( model, verbose=1 ).fit()
result.update_uncertainty()
# now begins the process of extracting results ... much fiddlier!
# start by defining the column names
colnames = 'pts_key psf_xcenter psf_ycenter psf_xcenter_unc psf_ycenter_unc psf_logflux psf_logflux_unc'.split()
# create an empty dictionary to hold column data as a list of values
data_dict = { col : [] for col in colnames }
# step through each model in the group of models
for node in model.parameters.nodes.values() :
# a sky component behaves differently and shouldn't be reported
if 'sky' in node.name :
continue
# now extract and store each quantity carefully.
data_dict[ 'objid' ].append( int(node.name) )
xcen, ycen = node['center'].value.detach().cpu().numpy()
dx, dy = node['center'].uncertainty.detach().cpu().numpy()
data_dict[ 'psf_xcenter' ].append( xcen )
data_dict[ 'psf_ycenter' ].append( ycen )
data_dict[ 'psf_xcenter_unc' ].append( dx )
data_dict[ 'psf_ycenter_unc' ].append( dy )
flux = node['flux'].value.detach().cpu().numpy()
dflux = node['flux'].uncertainty.detach().cpu().numpy()
data_dict[ 'psf_logflux' ].append( flux )
data_dict[ 'psf_logflux_unc' ].append( dflux )
# finally use this dictionary of lists to construct an astropy table of results
psf_data = Table( data_dict )
I recognise that the pattern one should use is specific to use case, and that the point of astrophot is that it is structured to be applicable to many and varied situations. So actually conceiving of a unified scheme for 'just works' dumping of data into a table is probably a fool's errand. But it might make sense to have some facility to do some common/likely use cases like the ones above?
But regardless, it would be very helpful to have a tutorial notebook that includes some examples and/or guidance for best practice ways of constructing catalogues/tables of results from astrophot.