njcuk9999 / apero-drs Goto Github PK
View Code? Open in Web Editor NEWA PipelinE to Reduce Observations - The DRS for SPIRou (CFHT)
License: MIT License
A PipelinE to Reduce Observations - The DRS for SPIRou (CFHT)
License: MIT License
cal_WAVE_E2DS_spirou not written in new DRS version.
@melissa-hobson suggested to update old DRS version.
Selected order in one of the plots doesn't show correct order edges
function = sPlt.slit_sorder_plot(p, loc, data2)
The solution should be to apply a -1 and +1 offset in yfit1 and yfit2 (instead of a +2 and 0 offset)
Request from Kanoa Withington
Dependencies and python package versions: we will need a list of dependency versions the pipeline has been tested against. Something in a versioned text file is fine.
Need's testing and updating accordingly.
@melissa-hobson can you confirm when you have tested this?
Need's testing and updating accordingly
@FrancoisBouchy needs to provide some files to test the DRS.
Files required are as follows:
Any other files provided should be given with the required recipes to test them on.
Cannot create an exposure-meter using the code written for H2RG data until we have DRS working up to (and including) cal_extract_RAW_spirou.py (and the wave solution recipes from the old DRS).
Therefore need a crude exposure-meter mask while we get the DRS ready.
Quality control failure reporting for numbers should be limited to 2 or 3 decimal places!
Check for all recipes!
Error when running code in GMT+2
if t_fmt_unix != t:
lock.close()
os.remove(lock_file)
emsg1 = 'Human time = {0} does not match unix time = {1} in calibDB'
emsg2 = ' - function = {0}'.format(func_name)
WLOG('error', p['log_opt'], [emsg1.format(t_fmt, t_human), emsg2])
Requires all recipes (up to and including cal_extract_RAW_spirou.py) to be working with H4RG data. Then should be easy to produce mask for the exposure-meter.
Feature request:
A user should not have to update the config.py file every time a new version is released
A file should be located anywhere the user wishes
Should be compatibility for two users using the same installation (i.e. a switch available to switch between config files - i.e. update the config path in the environmental variables)
A switch will need writing that is edited and run using source script.sh
Need's testing and updating accordingly
The function sort_version
in spirouStartup.py, expects the string returned by sys.version
to be delimited by the |
character, and have at least 2 parts. This isn't the case, at least on some systems.
Also, probably worth noting the python docs say the following about the string:
Do not extract version information out of it, rather, use version_info and the functions provided by the platform module.
Currently cal_DARK and cal_BADPIX write a "BAXPIX" file to calibDB thus later when BAXPIX file is used it depends on the running order of cal_DARK and cal_BADPIX (and on the date in the dark_dark file used for cal_DARK compared to the flat_flat file used in cal_BADPIX).
cal_DARK BADPIX file is crude and unneeded --> use cal_BADPIX for bad pixel mask
Currently, the source dictionary is not case-insensitive (as it is just a dictionary) this needs to be fixed.
In installation (and other codes) must have .py on the end of recipes
for example:
cal_validate_spirou
must be
cal_validate_spirou.py
to run from the command line
As we have the need for both H2RG and H4RG images we may need way to switch between them and test
them as needed
This should probably be in constants_SPIROU.py
maybe for example:
ic_image_type="H2RG"
But the main change will be "DRS_UCONFIG" (set in config.py
or as an environmental variable)
DRS_UCONFIG = '~/spirou_config_H2RG/'
DRS_UCONFIG = '~/spirou_config_H4RG/'
Then in ~/spirou_config_HXRG/config.py
and ~/spirou_config_HXRG/constants_SPIROU.py
the differing constants can be set (including the switch ic_image_type="H2RG"
or ic_image_type="H4RG"
Identified in cal_FF_RAW_spirou.py
but will also be a problem for all extraction.
Currently cal_loc_RAW_spirou.py
currently calculates the localization fits using a polynomial, but does not save (or even identify) where (in the x-direction) to start and stop. Therefore any point in recipes where the localization fits are used will use the fit from x positions between 0 and the maximum x-dimension pixel (normally image.shape[1]
). This is fine for orders that cover the entire range (from 0 to image.shape[1]
but not good for orders which have partial coverage. Here the fits can be bad (cross orders or have negative y-pixel values) where the fit was not originally valid (i.e. out of bounds).
Below shows an example where order 0 (bottom order) is being fit out of bounds (even when in-bounds the polynomial fit is fine).
In cal_FF_RAW_spirou.py
this has the effect of causing a value error (when trying to access an image at pixels that are negative) where one of the dimensions is zero. It is even worse when we do not have negative pixels (as the extracted values will just be wrong either from between order or other orders).
The error (and traceback) in cal_FF_RAW_spirou.py
is as follows:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/scratch/Projects/spirou_py3/spirou_py3/INTROOT/bin/cal_FF_RAW_spirou.py in <module>()
368 if __name__ == "__main__":
369 # run main with no arguments (get from command line - sys.argv)
--> 370 ll = main()
371 # exit message if in debug mode
372 spirouStartup.Exit(ll)
/scratch/Projects/spirou_py3/spirou_py3/INTROOT/bin/cal_FF_RAW_spirou.py in main(night_name, files)
214 # extract this order
215 eargs = [p, loc, data2, order_profile, order_num]
--> 216 e2ds, cpt = spirouEXTOR.ExtractTiltWeightOrder2(*eargs)
217 # calculate the noise
218 range1, range2 = p['IC_EXT_RANGE1'], p['IC_EXT_RANGE2']
/scratch/Projects/spirou_py3/spirou_py3/INTROOT/SpirouDRS/spirouEXTOR/spirouEXTOR.py in extract_tilt_weight_order2(pp, loc, image, orderp, rnum, **kwargs)
324 sigdet=kwargs.get('sigdet', pp['sigdet']))
325 # get the extraction for this order using the extract wrapper
--> 326 cent, cpt = extract_wrapper(*eargs, **ekwargs)
327 # return
328 return cent, cpt
/scratch/Projects/spirou_py3/spirou_py3/INTROOT/SpirouDRS/spirouEXTOR/spirouEXTOR.py in extract_wrapper(image, pos, sig, **kwargs)
498 # return extract(**ekwargs)
499 if mode == 2:
--> 500 return extract_tilt_weight2(**ekwargs)
501 if mode == 3:
502 return extract_tilt_weight_old2(**ekwargs)
/scratch/Projects/spirou_py3/spirou_py3/INTROOT/SpirouDRS/spirouEXTOR/spirouEXTOR.py in extract_tilt_weight2(image, pos, tilt, r1, r2, orderp, gain, sigdet)
803 ww = wwa[(ww0i, ww1i)]
804 # multiple the image by the rotation matrix
--> 805 sx = image[j1s[ic]:j2s[ic] + 1, i1s[ic]:i2s[ic] + 1] * ww
806 # multiple the order_profile by the rotation matrix
807 fx = orderp[j1s[ic]:j2s[ic] + 1, i1s[ic]:i2s[ic] + 1] * ww
ValueError: operands could not be broadcast together with shapes (0,5) (30,5)
Pre-processing requires Etienne's processing code (see below).
Needs converting to be compatible with DRS.
import numpy as np
import os
import sys
from astropy.io import fits as pyfits # --> rendered obsolete by the use of the more recent astropy.io.fits
import scipy
import scipy.ndimage
import matplotlib.pyplot as plt
def ref_top_bottom(im):
# correction of top and bottom reference pixels
imdim=4096
yfrac = (np.repeat(np.asarray(range(imdim)) / (imdim - 1.0), imdim // 64)).reshape(imdim, imdim // 64)
for j in range(32): # looping through the 32 outputs
for oddeven in range(2):
bottom = np.nanmedian(im[0:4, j * imdim // 32 + np.arange(64)*2+oddeven ])
top = np.nanmedian(im[imdim - 4:imdim, j * imdim // 32 + np.arange(64)*2+oddeven ])
im[:,j * imdim // 32 + np.arange(64)*2+oddeven] -= (top * yfrac + bottom * (1 - yfrac))
return (im)
# from astropy.io import fits as pyfits
# syntax -- python medampcorr.py files*fits
#
# will write cfilesXXX.fits (adds prefix)
# after subtracting the median of the first 5 amplifiers (number of
# unilluminated amps to be changed)
#
arg=np.asarray(sys.argv)
arg=arg[1:] # first argument is simply the name of the program and needs to be removed
fics = arg # we expect only files names. Will crash if the file does not exist
n=1 # keeping track of the file in the sequence
nn=len(fics)
for fic in fics:
fic2=fic.split('/')
if (fic2[len(fic2) - 1])[0] != 'c':
fic2[len(fic2)-1] = 'c'+fic2[len(fic2)-1]
outname="/".join(fic2)
# we skip any file that begins with "c"
# some outputs to keep the overeager astronomer happy
print('')
print( '['+str(n)+'/'+str(nn)+'] We process '+fic+' --> '+outname )
# just to avoid an error message with writeto
if os.path.isfile(outname):
print('file : '+outname+' exists, we are overwriting it')
os.system('rm '+outname)
# read the 1st extension
im=pyfits.getdata(fic,1)
h=pyfits.getheader(fic)
# subtract the common amplifier of unilluminated pixels
#n_unilum=7 # use the first n_unilum amplifiers
# may be modified at a later time. No need to pass it as an
# input as this will be fixed once we have the position of
# all diffraction orders
namp = 5
itime = h['INTTIME']
#robust_sig = np.nanmedian(np.abs(im[:,0:128*namp+128] - np.nanmedian(im[:,0:128*namp+128]))) / 0.675 * itime
# sigma-clipping at +-3 sigma
# g=np.where( np.abs(im-np.median(im)) < 3*robust_sig/itime )
# rms2=np.std(im[g])*itime
#print('Before filter -> STDEV (robust) : ' + '{:7.4f}'.format(robust_sig) + ' ADUs')
# correcting for the top and bottom ref pixels
im = ref_top_bottom(im)
xribbon = np.array([255,256,511,512])
xneighbours = np.array([254,257,510,513])
# we extract a box with the dark amplifiers + one for the median filtering
im2=im[:,0:(namp+1)*128]
im2b=im2+0
im2b[:,xribbon]=np.nan
# we produce a median-binned image
ybinnum=32 # --> 128=finer bins, 32=big bins
binstep=4096//ybinnum #
xbinnum=(namp + 1) * 128 // binstep
imbin = np.zeros([ybinnum,xbinnum])
for i in range(ybinnum):
for j in range(xbinnum):
x0=i*binstep#-binstep//2
y0=j*binstep#-binstep//2
x1=i*binstep+binstep#//2
y1=j*binstep+binstep#//2
imbin[i,j] = np.nanmedian(im2b[x0:x1,y0:y1])
im3=scipy.ndimage.zoom(imbin,binstep, order=2)
#pyfits.writeto('test.fits',im2b-im3,clobber=True)
#stop
diff=im2-im3 # we subtract the low-frequency part of the image. This leaves the common structures
# cube that contains the N amplifiers
common=np.zeros([namp,4096,128],dtype=float)
for i in range(namp):
if (i % 2) ==1 :
common[i, :, :] = diff[:, i * 128 + 128-1:i * 128-1:-1]
else:
# you need to flip the x axis between odd and even amps
common[i,:,:]=diff[:,i*128:i*128+128]
# the median amplifier
ref_amp=np.nanmedian(common,axis=0)
#subtracting it
for i_amp in range(32):
if (i_amp % 2) == 1 :
im[:, i_amp * 128 + 128 - 1:i_amp * 128 - 1:-1]-=ref_amp
else:
im[:, i_amp * 128:i_amp * 128 + 128]-=ref_amp
#robust_sig = np.nanmedian(np.abs(im[:,0:128*namp+128] - np.nanmedian(im[:,0:128*namp+128]))) / 0.675*itime
#print(' After filter -> STDEV (robust) : '+'{:7.4f}'.format(robust_sig)+ ' ADUs')
noise1f = scipy.ndimage.median_filter( np.nanmedian( im[:,np.array([0,1,2,3,4096-4,4096-3,4096-2,4096-1])],axis=1 ) ,size=binstep, mode='reflect')
#plt.plot(noise1f)
#
for i in range(4096):
im[:,i]-=noise1f
#
#for icol in range(4096):
# im[:,icol]-=noise1f
#pyfits.writeto('im2b.fits',im2b,clobber=True)
# we put everything in the same format as before
hdu1 = pyfits.PrimaryHDU()
hdu1.header = h
hdu1.header['NEXTEND'] = 4
im=np.rot90(im, -1) # rotation to match HARPS orientation
hdu2 = pyfits.ImageHDU(im)
new_hdul = pyfits.HDUList([hdu1, hdu2])
new_hdul.writeto(outname, overwrite=True)
else:
print('['+str(n)+'/'+str(nn)+'] '+fic+' is already a cleaned file!')
n+=1
For sPlt.ext_aorder_fit()
and sPlt.ext_sorder_fit
need edges "range1" and "range2" for fiber types A B C and AB (currently just plots middles) - i.e. center of AB and C only
E.g., if night is AT5-12/2018-03-09_19-18-06/
the returned full path would be /data/spirou1/raw/AT5-12/2018-03-09_19-18-06/AT5-12/2018-03-09_19-18-06/dark_dark02d405.fits
. Seems to be because the night is already there in arg_file_dir
.
The ACQTIME1 header key (human-readable date) is no longer in the header for H4RG files, which means spirouCDB.py.update_database() crashes. The following keys exist instead:
DATE = '2018-04-09T18:48:25' / UTC Date of file creation
HSTTIME = 'Mon Apr 09 08:48:25 HST 2018' / Local time in Hawaii
DATE-OBS= '2018-04-09' / Date at start of observation (UTC)
UTIME = '18:37:50.75' / Time at start of observation (UTC)
UTC-OBS = '18:37:50.75' / Time at start of observation (UTC)
DATEEND = '2018-04-09' / Date at end of observation (UTC)
UTCEND = '18:48:28.26' / Time at end of observation (UTC)
Note that the DATE key lacks precision compared to the old ACQTIME1 key, and is formatted slightly differently:
ACQTIME1= '2017-10-23-09:28:26.894' /UTC time (YYYY-MM-DD HH:MM:SS.MS)
Need's testing and updating accordingly
@melissa-hobson config.txt in documentation needs to be config.py
Found on multiple installations on different machines.
Once DRS runs with graphs, graphs are completely unusable and anything other than closing (i.e. zooming) crashes python and freezes up the computer.
When updating my local copy, I found the cal_preprocess_spirou.py recipe in INTROOT wasn't executable, as the others were previously made executable explicitly via chmod +x during the installation. Is there a way to add this to a recipe (perhaps cal_validate?) so the user doesn't have to do it manually?
Need's testing and updating accordingly
Found by Claire.
calls such as this:
cal_DARK_spirou.py AT5-12/2018-03-09_19-18-06/ dark_dark02f19.fits
Work but give a filename as follows:
_dark_dark02d405.fits
_dark_dark02d405_badpixel.fits
This is due to the normal date of the file being taken from the "night name"
i.e. for above
p['ARG_NIGHT_NAME'] = "AT5-12/2018-03-09_19-18-06/"
would give a file prefix of prefix = ''
due to the following:
prefix = p['ARG_NIGHT_NAME'].split(/)[-1]
Need's testing and updating accordingly
cal_loc_RAW_spirou.py there were no holes in H2RG test data, need to figure out a way to fix this.
Etienne has proposed solution:
Request by Kanoa Withington:
License: The new version will need a license and it needs to be checked into the repository
There's a threshhold in find_order_centers in spirouLOCOR, line 310:
if np.max(ovalues) - np.min(ovalues) > (100.0 * sigdet):
That should probably be in the constants file (I'm testing changes to it for the H4RG images).
Noted that this:
# add the tilt parameters
for order_num in range(0, int(loc['number_orders']/2)):
# modify name and comment for keyword
tilt_keywordstore = list(p['kw_TILT'])
tilt_keywordstore[0] += str(order_num)
tilt_keywordstore[2] += str(order_num)
# add keyword to hdict
hdict = spirouImage.AddKey(hdict, tilt_keywordstore,
value=loc['tilt'][order_num])
can be replaced with AddKey1Dlist function
Currently, only fp files are allowed but should allow hc files as well
Also should double check diff between V48 and last fixes
Example workarounds in branch import-fixes, at commits 4374359, 59891f0, 4a3e295 (the spirouLOCOR.py fix is a lazy copy-paste).
Currently, file identification is done via file name "prefix" i.e. "dark_dark" "dark_flat" "fp_fp" eventually this will have to be changed to access certain header keys that are set at CFHT, and checked.
The input to the main function would be that a certain file type is required (i.e. dark or flat or fp etc)
Need's testing and updating accordingly
Noted by Claire
Any missing modules will cause cal_validate to fail with the following message:
Fatal error cannot import SpirouDRS
NSTALL folder must be on PYTHONPATH
although actually, it could be due to a missing module (like numpy or matplotlib)
dependencies should be checked before importing SpirouDRS
Code in question in cal_validate_spirou.py
:
# -------------------------------------------------------------------------
# SpirouDRS
# -------------------------------------------------------------------------
try:
# noinspection PyUnresolvedReferences
import SpirouDRS
if debug_mode:
debug_message(SpirouDRS.__NAME__)
except ImportError as e:
print('Fatal error cannot import SpirouDRS')
print('INSTALL folder must be on PYTHONPATH')
EXIT(1)
# if other exception try to read constants file and check paths
except Exception as e:
print('\tInstallation failed with message')
print('\t{0}'.format(e))
EXIT(1)
When argument "dtype" is used all images are saved to integers (pointed out by Melissa).
quick fix: do not use "dtype" --> works fine.
Need to fix this bug (but not urgent as one can use the quick fix)
quick fix:
Don't do:
spirouImage.WriteImage(rotatefits, data, hdict, dtype='float64')
Instead do:
spirouImage.WriteImage(rotatefits, data, hdict)
In some tests PYTHONPATH doesn't exist and hence breaks when appended to.
export PYTHONPATH=DRS_ROOT: DRS_ROOT/bin/:{$PYTHONPATH}
and
setenv PYTHONPATH DRS_ROOT: DRS_ROOT/bin/:{$PYTHONPATH}
For some reason, the documentation has weird <$PATH>
instead of {$PATH}
in Isabelle's version. This should be resolved (unless it is an old documentation issue)
Needs writing from the old version:
import string
import os.path
import sys
import time
import shutil
import ctools
import numpy as np
import spirouTHORCA
import spirouVISU
import hadmrMATH
import spirouFITS
import spirouBIAS
import spirouEXTOR
import spirouCDB
import hadrgdCONFIG
from numpy.oldnumeric import *
from extract2 import *
import matplotlib.pyplot as plt
import spirouRV
import fitpoly
s=string
FITS=spirouFITS
VISU=spirouVISU
tmp_file="%s"%int(time.time())
execfile(os.getenv('PYTHONSTARTUP'))
execfile(os.getenv('PYTHONSTARTUP2'))
###########################
###########################
fitsfilename=os.path.join(dir_data_reduc,arg_night_name,arg_file_names[0])
dirfits=os.path.join(dir_data_reduc,arg_night_name)
if os.path.exists(dirfits)==0:
WLOG('error',log_opt,'Directory :'+dirfits+' does not exist')
exit(1)
if os.path.exists(fitsfilename)==0:
WLOG('error',log_opt,'File: '+fitsfilename+' does not exist')
exit(1)
if string.find(arg_file_names[0],'hc')<0:
WLOG('error',log_opt,'Wrong type of image for cal_HC, should be hc')
exit(1)
if string.find(arg_file_names[0],'AB')>0:
fiber='AB'
elif string.find(arg_file_names[0],'C')>0:
fiber='C'
else:
WLOG('error',log_opt,'Fiber name not recognized, should be AB or C')
exit(1)
if locals().has_key('data'): del data
if locals().has_key('data2'): del data2
WLOG('',log_opt,'Reading File: '+fitsfilename)
data,nx,nbo=spirouFITS.read_data_raw(fitsfilename)
if len(arg_file_names)>1:
for i in range(len(arg_file_names)-1):
fitsfilename=os.path.join(dir_data_reduc,arg_night_name,arg_file_names[i+1])
WLOG('',log_opt,'Reading Image '+fitsfilename+ ' and added')
data2,nx2,nbo2=spirouFITS.read_data_raw(fitsfilename)
data=add(data,data2)
WLOG('',log_opt,'Image '+repr(nx)+'x'+repr(nbo)+' loaded')
ccdgain=spirouFITS.read_key(fitsfilename,'GAIN')
ccdsigdet=spirouFITS.read_key(fitsfilename,'RDNOISE')
exptime=spirouFITS.read_key(fitsfilename,'EXPTIME')
bjdref=spirouFITS.read_key(fitsfilename,'ACQTIME')
kw_CCD_SIGDET[1]=ccdsigdet
kw_CCD_CONAD[1]=ccdgain
#########################
#########################
cal_db=spirouCDB.get_master(ic_calib_db_master_file,spirouCDB.filename2tunix2(fitsfilename),log_opt)
if cal_db.has_key('NONE'):
WLOG('error',log_opt,'Missing CalibDB can not proceed')
exit(0)
spirouCDB.cp_db_files(dir_calib_db,os.path.join(dir_data_reduc,arg_night_name),cal_db,log_opt)
if cal_db.has_key('FLAT_'+fiber):
WLOG('',log_opt+fiber,'Doing Flat Correction')
flat_file=os.path.join(dir_data_reduc,arg_night_name,cal_db['FLAT_'+fiber][1])
flat,nx,ny=spirouFITS.read_data_raw(flat_file)
else:
flat=ones(shape(data),'d')
flat=where(flat==0.,1.,flat)
#data=data/flat
#################################
#################################
wave_fitsfilename={
'AB': os.path.join(dir_data_reduc,arg_night_name,s.split(arg_night_name,'/')[1]+'_'+s.replace(arg_file_names[0],'_e2ds_AB.fits','wave_AB.fits')),
'C': os.path.join(dir_data_reduc,arg_night_name,s.split(arg_night_name,'/')[1]+''+s.replace(arg_file_names[0],'_e2ds_C.fits','_wave_C.fits'))}
#################################
#################################
if string.find(arg_file_names[0],'hcone')>=0:
lamp='UNe'
elif string.find(arg_file_names[0],'hctwo')>=0:
lamp='TH'
else:
WLOG('error',log_opt,'Lamp type cannot be identified')
exit(1)
#lamp=FITS.read_key(fitsfilename,'INSLAMP')
th_LINES_={}
FINAL_ll_param_={}
FINAL_x_param_={}
FINAL_x_details_={}
FINAL_ll_details_={}
FINAL_iter_={}
ll_scale_={}
ll_out_={}
param_ll_out_={}
#param_x_out_={}
T_order_={}
#################################
#################################
if lamp=='UNe':
ic_ll_TH_line_file=dir_drs_config+'catalogue_UNe.dat'
cat='fullcat'
elif lamp=='TH':
ic_ll_TH_line_file=dir_drs_config+'catalogue_ThAr.dat'
cat='thcat'
#ic_ll_TH_line_file='/home/spirou/mhobson/wavelength/catalogue_ThAr_firstguess.dat' #ThAr ref line list
#cat='thtrimcat'
ic_ll_degr_fit=4 #default is 5
ic_ll_sp_min=900
ic_ll_sp_max=2400
ic_max_ampl_lines=2.e+8 #2.e+5 # max ampl th lines
ic_max_errw_onfit=1 # 1
#ic_max_sigll_cal_lines=0.1 # 5.2
ic_Resol= 55000 #50000 #60000
ic_ll_free_span=3 #3 #2.6
noise=30 #16.8
n_ord_final=24 #order to which the solution is calculated
ic_T_order_start=66 #echelle of first extracted order
ic_ll_smooth=0
plt.ion()
fib_typ=[fiber]
for fiber in fib_typ:
#################################
#################################
WLOG('info',log_opt+fiber,'Processing Wavelength Calibration for Fiber '+fiber)
T_order=-arange(0,n_ord_final,1)+ic_T_order_start*1.0
try:
cal_file=os.path.join(dir_data_reduc,arg_night_name,cal_db['WAVE_'+fiber][1]) ## To be used as soon as CalibDB has a good wavelentgh
except KeyError:
cal_file=dir_drs_config+'hcone_hcone02c406_blue_wave_new722_C.fits'
ll_init,param_ll_init=FITS.get_e2ds_ll(cal_file) #new function no longer requires kw
WLOG('',log_opt+fiber,'Reading initial wavelength solution in '+cal_file)
ll_init=ll_init[:n_ord_final] #fit is performed only on these orders
linefile=open(ic_ll_TH_line_file,'r') #wavelength file
ll_line=[]
Ampl_line=[]
for line_txt in linefile.readlines():
ll_line.append(float(s.split(line_txt)[0]))
Ampl_line.append(float(s.split(line_txt)[1]))
linefile.close()
WLOG('',log_opt+fiber,'List of '+"%s"%(len(ll_line))+' HC lines read in file '+ic_ll_TH_line_file)
#################################
#################################
WLOG('',log_opt+fiber,'On fiber '+fiber+' trying to identify lines using guess solution:')
th_LINES=spirouTHORCA.find_lines(ll_init,data[:n_ord_final],ic_ll_sp_min,ic_ll_sp_max,ic_Resol,
ic_ll_free_span,ll_line,Ampl_line,noise,log_opt+fiber,T_order)
#########################################################
#########################################################
WLOG('',log_opt+fiber,'On fiber '+fiber+' cleaning list of identified lines')
for i in (arange(len(th_LINES))):
bad_fit=sum(less_equal(th_LINES[i][:,7],ic_max_errw_onfit))
th_LINES[i][:,7]=choose(greater(th_LINES[i][:,7],ic_max_errw_onfit),
(zeros(len(th_LINES[i][:,7])),th_LINES[i][:,7]))
sigll=th_LINES[i][:,1]/th_LINES[i][:,0]*300000
th_LINES[i][:,7]=choose(less(sigll,ic_max_sigll_cal_lines),
(zeros(len(th_LINES[i][:,7])),th_LINES[i][:,7]))
bad_sig=sum(greater_equal(sigll,ic_max_sigll_cal_lines))
th_LINES[i][:,7]=choose(less(th_LINES[i][:,2],ic_max_ampl_lines),
(zeros(len(th_LINES[i][:,7])),th_LINES[i][:,7]))
bad_ampl=sum(greater_equal(th_LINES[i][:,2],ic_max_ampl_lines))
if (bad_sig>0)|(bad_ampl>0|(bad_fit>0)):
WLOG('',log_opt+fiber,'In Order '+"%s"%(i)+' reject ('+"%s/%s/%s"%(bad_sig,bad_ampl,bad_fit)+
') lines [beyond (sig/ampl/err) limits]')
th_LINES[i][:,7]=np.choose(~np.isinf(th_LINES[i][:,7]),(zeros(len(th_LINES[i][:,7])),th_LINES[i][:,7])) #removing infs
#########################
#########################
WLOG('',log_opt+fiber,'On fiber '+fiber+' fitting wavelength solution on identified lines:')
FINAL_xfit_moy,FINAL_xfit_var,FINAL_iter,FINAL_x_param,FINAL_x_details,ll_scale=
spirouTHORCA.fit_1Ds_ll_sol(ll_init,th_LINES,ic_ll_degr_fit,ic_errx_min,ic_wei_max
,ic_max_llfit_rms,log_opt+fiber,T_order,fiber)
if (hadmrMATH.isInf(FINAL_xfit_moy))|(hadmrMATH.isNaN(FINAL_xfit_moy)):
QC_failed='NaN or Inf occured!'
FINAL_llfit_moy,FINAL_llfit_var,FINAL_ll_param,FINAL_ll_details=
spirouTHORCA.invert_1Ds_ll_sol(ll_init,FINAL_x_param,FINAL_x_details,
add.reduce(FINAL_iter[:,2]),ic_ll_degr_fit,log_opt+fiber)
param_ll_out=reshape(FINAL_ll_param,(len(FINAL_ll_param),len(FINAL_ll_param[0])))
ll_out=spirouTHORCA.get_ll(len(data[:n_ord_final][0]),len(FINAL_ll_param),param_ll_out)
dll_out=spirouTHORCA.get_dll(len(data[:n_ord_final][0]),len(FINAL_ll_param),param_ll_out)
WLOG('info',log_opt+fiber,'On fiber '+fiber+' mean pixel scale at center: '+
"%.4f"%(sum(dll_out[:,len(ll_out[0])/2]/ll_out[:,len(ll_out[0])/2])/len(ll_out[:,len(ll_out[0])/2])*300000)+'[km/s/pixel]')
####### Extrapolation of param_ll_out for all spectral orders - NOT USED TO BE REMOVED LATER
##zeroth coefficients
##first coefficients
##second coefficients
##third coefficients
##fourth coefficients
#########################################
#########################################
th_LINES_[fiber]=th_LINES
FINAL_ll_param_[fiber]=FINAL_ll_param
FINAL_x_param_[fiber]=FINAL_x_param
FINAL_x_details_[fiber]=FINAL_x_details
FINAL_ll_details_[fiber]=FINAL_ll_details
FINAL_iter_[fiber]=FINAL_iter
ll_out_[fiber]=ll_out
ll_scale_[fiber]=ll_scale
param_ll_out_[fiber]=param_ll_out
T_order_[fiber]=T_order
N_blue_ord=n_ord_final
ic_order_init=0
ic_Littrow_fit_deg=5
sig_Littrow_ext=[]
moy_Littrow_ext=[]
mindev_Littrow_ext=[]
maxdev_Littrow_ext=[]
save_Littrow_param=[]
x_Littrow_cut_ext=[250,500,750,1000,1250,1500,1750] #points at which to evaluate the Littrow fit on each order
wgt_Littrow=T_order_[fiber]*0+1
if locals().has_key('ic_wgt_Littrow'):
for iorder in ic_wgt_Littrow[fiber]:
wgt_Littrow[iorder]=0.
for x in range(len(x_Littrow_cut_ext)): #do Littrow fit
Q=spirouTHORCA.view_Littrow(T_order_,ll_out_,fiber,wgt_Littrow,x_Littrow_cut_ext[x],ic_Littrow_fit_deg,N_blue_ord,ic_order_init,x>0,0,ic_debug)
moy_Littrow_ext.append(Q[0])
sig_Littrow_ext.append(Q[1])
mindev_Littrow_ext.append(Q[2])
maxdev_Littrow_ext.append(Q[3])
save_Littrow_param.append(Q[6])
Littrow_extrap = np.zeros((36,len(x_Littrow_cut_ext)),'d') #stores evaluated Littrow fits for the x_ext values on each order
Littrow_extrap_sol = np.zeros((36,len(data[0])),'d') #stores ll(x) for each order
param_Littrow_extrap=np.zeros((36,5),'d') #stores Littrow params for each order
for i in range(36): #evaluate the Littrow fit on the x_..._ext values for each order
for j in range(len(x_Littrow_cut_ext)):
aux=[]
for k in range(len(save_Littrow_param[j])):
aux.append(save_Littrow_param[j][k]*(1./(ic_T_order_start-i))**(k))
Littrow_extrap[i,j]=sum(aux)*ll_out[ic_order_init][x_Littrow_cut_ext[j]]
param=np.zeros(5,'d')
auxx=np.zeros(len(x_Littrow_cut_ext),'d')
fitpoly.fitpoly(x_Littrow_cut_ext,Littrow_extrap[i],param,auxx) #fit a polynomial to the 7 evaluated Littrow ll(x) on each order
param_Littrow_extrap[i]=param
for jj in range(len(data[0])): #evaluate the polyinomial in each x in (0,2035) for each order
aux2=[]
for kk in range(len(param)):
aux2.append(param[kk]*jj**kk)
Littrow_extrap_sol[i,jj]=sum(aux2)
plt.figure() #plot the points and function for each order
for i in range(36):
plt.plot(x_Littrow_cut_ext,Littrow_extrap[i],'o')
plt.plot(np.arange(len(data[0])),Littrow_extrap_sol[i])
#########################################
#########################################
ic_ll_free_span=2.6 #3 #reducing slightly as it's the second loop
n_ord_final_2=24 # can't go above 34 - above 24 is more distorted, less consistent for passing QC
T_order=-arange(0,n_ord_final_2,1)+ic_T_order_start*1.0
ll_line_2=[]
Ampl_line_2=[]
for i in range(n_ord_final):
for j in range(len(FINAL_x_details[i][0])):
ll_line_2.append(FINAL_x_details[i][0][j])
Ampl_line_2.append(FINAL_x_details[i][3][j])
maxll=max(ll_line_2)
for i in range(len(ll_line)):
if ll_line[i]>maxll:
ll_line_2.append(ll_line[i])
Ampl_line_2.append(Ampl_line[i])
WLOG('',log_opt+fiber,'On fiber '+fiber+' trying to identify lines using guess solution (second pass):')
th_LINES_2=spirouTHORCA.find_lines(Littrow_extrap_sol[:n_ord_final_2],data[:n_ord_final_2],ic_ll_sp_min,ic_ll_sp_max,ic_Resol,
ic_ll_free_span,ll_line_2,Ampl_line_2,noise,log_opt+fiber,T_order)
WLOG('',log_opt+fiber,'On fiber '+fiber+' cleaning list of identified lines (second pass)')
for i in (arange(len(th_LINES_2))):
bad_fit=sum(less_equal(th_LINES_2[i][:,7],ic_max_errw_onfit))
th_LINES_2[i][:,7]=choose(greater(th_LINES_2[i][:,7],ic_max_errw_onfit),
(zeros(len(th_LINES_2[i][:,7])),th_LINES_2[i][:,7]))
sigll=th_LINES_2[i][:,1]/th_LINES_2[i][:,0]*300000
th_LINES_2[i][:,7]=choose(less(sigll,ic_max_sigll_cal_lines),
(zeros(len(th_LINES_2[i][:,7])),th_LINES_2[i][:,7]))
bad_sig=sum(greater_equal(sigll,ic_max_sigll_cal_lines))
th_LINES_2[i][:,7]=choose(less(th_LINES_2[i][:,2],ic_max_ampl_lines),
(zeros(len(th_LINES_2[i][:,7])),th_LINES_2[i][:,7]))
bad_ampl=sum(greater_equal(th_LINES_2[i][:,2],ic_max_ampl_lines))
if (bad_sig>0)|(bad_ampl>0|(bad_fit>0)):
WLOG('',log_opt+fiber,'In Order '+"%s"%(i)+' reject ('+"%s/%s/%s"%(bad_sig,bad_ampl,bad_fit)+
') lines [beyond (sig/ampl/err) limits]')
th_LINES_2[i][:,7]=np.choose(~np.isinf(th_LINES_2[i][:,7]),(zeros(len(th_LINES_2[i][:,7])),th_LINES_2[i][:,7])) #removing infs
WLOG('',log_opt+fiber,'On fiber '+fiber+' fitting wavelength solution on identified lines (second pass):')
FINAL_xfit_moy,FINAL_xfit_var,FINAL_iter,FINAL_x_param,FINAL_x_details,ll_scale=
spirouTHORCA.fit_1Ds_ll_sol(Littrow_extrap_sol[:n_ord_final_2],th_LINES_2,ic_ll_degr_fit,ic_errx_min,ic_wei_max
,ic_max_llfit_rms,log_opt+fiber,T_order,fiber)
if (hadmrMATH.isInf(FINAL_xfit_moy))|(hadmrMATH.isNaN(FINAL_xfit_moy)):
QC_failed='NaN or Inf occured!'
FINAL_llfit_moy,FINAL_llfit_var,FINAL_ll_param,FINAL_ll_details=
spirouTHORCA.invert_1Ds_ll_sol(Littrow_extrap_sol[:n_ord_final_2],FINAL_x_param,FINAL_x_details,
add.reduce(FINAL_iter[:,2]),ic_ll_degr_fit,log_opt+fiber)
param_ll_out_2=reshape(FINAL_ll_param,(len(FINAL_ll_param),len(FINAL_ll_param[0])))
ll_out_2=spirouTHORCA.get_ll(len(data[:n_ord_final_2][0]),len(FINAL_ll_param),param_ll_out_2)
dll_out_2=spirouTHORCA.get_dll(len(data[:n_ord_final_2][0]),len(FINAL_ll_param),param_ll_out_2)
WLOG('info',log_opt+fiber,'On fiber '+fiber+' mean pixel scale at center: '+
"%.4f"%(sum(dll_out_2[:,len(ll_out_2[0])/2]/ll_out_2[:,len(ll_out_2[0])/2])/len(ll_out_2[:,len(ll_out_2[0])/2])*300000)+'[km/s/pixel]')
#########################
#########################
ic_x_Littrow_cut=[500,1000,1500]
th_LINES_[fiber]=th_LINES
FINAL_ll_param_[fiber]=FINAL_ll_param
FINAL_x_param_[fiber]=FINAL_x_param
FINAL_x_details_[fiber]=FINAL_x_details
FINAL_ll_details_[fiber]=FINAL_ll_details
FINAL_iter_[fiber]=FINAL_iter
ll_out_[fiber]=ll_out_2
ll_scale_[fiber]=ll_scale
param_ll_out_[fiber]=param_ll_out_2
T_order_[fiber]=T_order
N_blue_ord=n_ord_final_2
ic_order_init=0
ic_Littrow_fit_deg=5
sig_Littrow=[]
moy_Littrow=[]
mindev_Littrow=[]
maxdev_Littrow=[]
x_Littrow_cut=ic_x_Littrow_cut
wgt_Littrow=T_order_[fiber]*0+1
if locals().has_key('ic_wgt_Littrow'):
for iorder in ic_wgt_Littrow[fiber]:
wgt_Littrow[iorder]=0.
plt.figure()
plt.clf()
for x in range(len(x_Littrow_cut)):
Q=spirouTHORCA.view_Littrow(T_order_,ll_out_,fiber,wgt_Littrow,x_Littrow_cut[x],ic_Littrow_fit_deg,N_blue_ord,ic_order_init,x>0,0,ic_debug)
moy_Littrow.append(Q[0])
sig_Littrow.append(Q[1])
mindev_Littrow.append(Q[2])
maxdev_Littrow.append(Q[3])
WLOG('info',log_opt+fiber,'Littrow check at X='+"%s"%(x_Littrow_cut[x])+' mean:'+"%6.3f"%(Q[0]*1000)+'[m/s] rms:'+
"%6.2f"%(Q[1]*1000)+' [m/s] min/max:'+"%6.2f/%6.2f [m/s]"%(Q[2]*1000,Q[3]*1000)+
" (frac: %4.1f/%4.1f)"%(Q[2]/Q[1],Q[3]/Q[1]))
VISU.megaplot(Q[4],Q[5],xtitle='#order',ytitle='Diff/Littrow [km/s]',
title='Wavelength Solution Littrow Check fiber '+fiber,
xmin=int(Q[4][0]+1),xmax=int(Q[4][-1]-1),ymin=-1,ymax=1,overplot=x>0)
#########################################
#########################################
ll_out_3=np.vstack((ll_out_2,Littrow_extrap_sol[n_ord_final_2:]))
param_ll_out_3=np.vstack((param_ll_out_2,param_Littrow_extrap[n_ord_final_2:]))
#########################################
#########################################
WLOG('',log_opt,'Write wavelength Solution of Fiber '+fiber+' in '+os.path.split(fitsfilename)[1])
spirouFITS.put_e2ds_ll_param(fitsfilename,param_ll_out_3)
WLOG('',log_opt,'Saving wavelength array of Fiber '+fiber+' in '+os.path.split(wave_fitsfilename[fiber])[1])
spirouFITS.write_data(wave_fitsfilename[fiber], ll_out_3)
spirouFITS.copy_key(fitsfilename,wave_fitsfilename[fiber])
#################################
#################################
res_tbl_file=os.path.join(dir_data_reduc,arg_night_name,'cal_HC_result.tbl')
try:
file=open(res_tbl_file)
except IOError:
file=open(res_tbl_file,'w')
file.write('night_name'+ '\t' +'file_name'+ '\t' +'fiber'+ '\t' +'mean'+
'\t' +'rms'+ '\t' +'N_lines'+ '\t' +'err'+
'\t' +'rms_L0'+ '\t'+'rms_L1'+ '\t'+'rms_L2'+'\t'+'drift'+'\t'+'drift2'+'\t'+'Rflux'+'\t'+'Ccosmic'+
'\t' +'error_spe'+'\n')
file.write('----------'+ '\t' +'---------'+ '\t' +'-----'+ '\t' +'---'+
'\t' +'---'+ '\t' +'-------'+ '\t' +'---'+
'\t' +'------'+ '\t'+'------'+ '\t'+'------'+'\t'+'-----'+'\t'+'------'+'\t'+'-----'+'\t'+'-------'+
'\t' +'---------'+'\n')
file.close()
os.chmod(res_tbl_file,0664)
try:
file=open(res_tbl_file,'a')
except IOError:
WLOG('error',log_opt+fiber,'I/O error on file: '+res_tbl_file)
exit(0)
file.write(arg_night_name+'\t'+arg_file_names[0]+'\t'+fiber+'\t'+
"%7.4f\t"%(FINAL_xfit_moy*1000)+
"%6.2f"%(sqrt(FINAL_xfit_var)*1000)+'\t'+
"%i"%add.reduce(FINAL_iter[:,2])+'\t'+
"%6.3f"%(sqrt(FINAL_xfit_var/add.reduce(FINAL_iter[:,2]))*1000)+'\t'+
"%6.2f"%(sig_Littrow[0]*1000)+'\t'+
"%6.2f"%(sig_Littrow[1]*1000)+'\t'+
"%6.2f\n"%(sig_Littrow[2]*1000))
file.close()
WLOG('',log_opt+fiber,'Global result summary saved in '+res_tbl_file)
#################################
#################################
res_tbl_line_file=os.path.join(dir_data_reduc,arg_night_name, s.replace(arg_file_names[0],'.fits','hc_lines'+fiber+'.tbl'))
file=open(res_tbl_line_file,'w')
file.write('order\tll\tdv\tw\txi\txo\tdvdx\n')
file.write('-----\t--\t--\t-\t--\t--\t----\n')
for i in range(len(FINAL_x_details)):
for j in range(len(FINAL_x_details[i][0])):
file.write("%2i"%i+'\t'+"%12.4f"%FINAL_x_details[i][0][j]+'\t'+"%13.5f"%FINAL_ll_details[i][0][j]+'\t'
+"%12.4f"%FINAL_x_details[i][3][j]+'\t'+"%12.4f"%FINAL_x_details[i][1][j]+'\t'+"%12.4f"%FINAL_x_details[i][2][j]+'\t'+"%8.4f"%ll_scale[i][j]+'\n')
file.close()
WLOG('',log_opt+fiber,'List of lines used saved in '+res_tbl_line_file)
#################
#################
qc_rms_littrow_max=[0.300,0.300,0.300] # max Littrow deviation for ll sol at X=700,1200,1700
qc_dev_littrow_max=[0.900,0.900,0.900] # max Littrow
if not(locals().has_key('QC_failed')):
for x in range(len(x_Littrow_cut)):
if (sig_Littrow[x] >qc_rms_littrow_max[x])|
(max(abs(maxdev_Littrow[x]),abs(mindev_Littrow[x])) >qc_dev_littrow_max[x]):
QC_failed='Littrow test x='+"%s"%(x_Littrow_cut[x])
WLOG('error',log_opt+fiber,'On fiber '+fiber+ ' QC failed for: '+QC_failed)
if locals().has_key('QC_failed'):
kw_drs_QC[1]='FAILED'
else:
WLOG('info',log_opt+fiber,'On fiber '+fiber+' QUALITY CONTROL SUCCESSFUL - Well Done -')
#########################
#########################
spirouFITS.update_key_2(fitsfilename,kw_drs_QC)
spirouFITS.update_key_2(wave_fitsfilename[fiber],kw_drs_QC)
#########################
#########################
wave={}
param_ll={}
cor_fitsfilename={
'AB': os.path.join(dir_data_reduc, arg_night_name, string.replace(arg_file_names[0],
'.fits','ccf'+'HC'+'_AB.fits')),
'C': os.path.join(dir_data_reduc, arg_night_name, string.replace(arg_file_names[0],
'.fits','ccf'+'HC'+'_C.fits'))}
res_tbl_file={
'C': string.replace(cor_fitsfilename['C'],'.fits','.tbl'),
'AB': string.replace(cor_fitsfilename['AB'],'.fits','.tbl')}
for fiber in fib_typ:
if lamp=='UNe':
ic_hc_mask=dir_drs_config+'test_mask_UNe_firstguess_R50000.mas'
elif lamp=='TH':
ic_hc_mask=dir_drs_config+'test_mask_TH_R50000.mas'
wave[fiber],param_ll[fiber]=spirouFITS.get_e2ds_ll(fitsfilename)
RV_template=ic_hc_mask
ll_mask_D,ll_mask_ctr,w_mask=spirouRV.get_mask(RV_template,1,0,log_opt)
ic_thorium_CCF_half_width=10
ic_thorium_CCF_step=0.1
RV_CCF=arange(-ic_thorium_CCF_half_width,ic_thorium_CCF_half_width+ic_thorium_CCF_step,ic_thorium_CCF_step)
CCF,CCF_max,pix_passed_all,tot_line,ll_range_all,CCF_noise=
spirouRV.coravelation(wave[fiber],data,param_ll[fiber],data*0.+1.,
RV_CCF,ll_mask_D,ll_mask_ctr,w_mask,0,0,noise,res_tbl_file[fiber],1,0)
average_CCF=sum(CCF)
normalized_CCF=average_CCF/max(average_CCF)
CCF_res,CCF_fit=spirouRV.fit_CCF(RV_CCF,normalized_CCF,1)
RV_CCF=arange(CCF_res[1]-ic_thorium_CCF_half_width,CCF_res[1]+ic_thorium_CCF_half_width+ic_thorium_CCF_step,ic_thorium_CCF_step)
CCF,CCF_max,pix_passed_all,tot_line,ll_range_all,CCF_noise=
spirouRV.coravelation(wave[fiber],data,param_ll[fiber],data*0.+1.,
RV_CCF,ll_mask_D,ll_mask_ctr,w_mask,0,0,noise,res_tbl_file[fiber],1,0)
average_CCF=sum(CCF)
normalized_CCF=average_CCF/max(average_CCF)
CCF_res,CCF_fit=spirouRV.fit_CCF(RV_CCF,normalized_CCF,1)
CCF_res[0]=CCF_res[0]/(1.+CCF_res[3])
summary='calibrated CCF at RV= %.3f km/s'%(CCF_res[1])
#########################
#########################
#########################
#########################
e2dscopy_fitsfilename = os.path.split(fitsfilename)[0]+'/'+s.split(arg_night_name,'/')[1]+'_'+os.path.split(fitsfilename)[1]
shutil.copyfile(fitsfilename,e2dscopy_fitsfilename) #makes a properly-named copy of the e2ds file for the calibdb
for fiber in fib_typ:
if not(locals().has_key('QC_failed')):
spirouCDB.put_file(dir_calib_db,wave_fitsfilename[fiber],log_opt)
spirouCDB.update_master(ic_calib_db_master_file,arg_night_name,'WAVE_'+fiber,os.path.split(wave_fitsfilename[fiber])[1],log_opt+fiber)
spirouCDB.put_file(dir_calib_db,e2dscopy_fitsfilename,log_opt)
spirouCDB.update_master(ic_calib_db_master_file,arg_night_name,'HCREF_'+fiber,os.path.split(e2dscopy_fitsfilename)[1],log_opt+fiber)
WLOG('info',log_opt,'Recipe '+process_running+' has been successfully completed')
####################################################
def view_iter(order,iter,fiber):
###################################################
wei=THORCA.fit_sol.all_details[order][iter][3]
x=THORCA.fit_sol.all_details[order][iter][0]
diff=(THORCA.fit_sol.all_details[order][iter][2]-THORCA.fit_sol.all_details[order][iter][1])
for i in range(len(x)):
print "%6.2f"%(x[i])+"%8.2f"%(diff[i])+"%8.2f"%(1/sqrt(wei[i]))+"%8.2f"%(diff[i]sqrt(wei[i]))
VISU.megaplot(x,diffsqrt(wei),typo='points',xmin=x[0],xmax=x[-1])
VISU.megaplot(x,diff/max(diff),overplot=1,typo='points')
VISU.megaplot(x,diff/max(diff),overplot=1,typo='points')
####################################################
def view_iter2(order,iter,fiber):
###################################################
wei=THORCA.fit_sol.all_details[order][iter][3]
x=THORCA.fit_sol.all_details[order][iter][0]
diff=(THORCA.fit_sol.all_details[order][iter][2]-THORCA.fit_sol.all_details[order][iter][1])
VISU.Points(x,diff,0,0,0,0,0,
'iter:'+"%s"%iter+' rms:'+"%5.3f"%sqrt(THORCA.fit_sol.all_iter[order][iter][1]))
L=ll_out_[fiber][order,:]
F=data[:n_ord_final][order,:]
VISU.Histo2(L,F,0,0,5000,0,0,'')
@melissa-hobson needs to decide which one needs porting into python 3.
Decide between:
H4RG images are rotated 90 degrees from H2RG images. Where do we do the rotation, and how to do it without making the DRS incompatible for H2RG images? Options I see:
a) In spirouFITS.read_raw_data, using a check to ensure we only rotate raw H4RG images (as presumably e2ds files will be saved in the correct orientation)?
b) With a separate function in spirouFITS, called using a check so it will only be applied to raw H4RG images?
config.txt
is present in quick installation and installation should be config.py
kind = "Flatfield" however this is wrong
When calibDB is empty code exits (correctly), however for cal_BADPIX and cal_DARK no keys are required in calibDB thus they should be allowed to have an empty calibDB file.
check functions: sPlt.ff_aorder_fit_edges
and sPlt.ff_sorder_fit_edges
This is expected due to design, however it was not present in the H2RG data therefore this needs to be added.
Etienne's suggestion: "threshold" below which we do not continue measuring flux for the localization fits.
How are these limits stored for each order (if they need to be stored)?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.