def determineCoordsFromImage(self, imageFileName): configFolder = self.ppl["CONFIG_FOLDER"] if configFolder == None: configFolder = "$HOME/.pmlib" SOLVE_ARGS = "-O --config " + configFolder + "/astrometry.cfg --use-sextractor --sextractor-path sextractor -r -y -p" makedirs("temp", exist_ok = True) invoke("cp " + imageFileName + " temp/src.fits") astFolder = self.ppl["AST_BIN_FOLDER"] if astFolder == None: astFolder = "/usr/local/astrometry/bin" astResult = invoke(astFolder + "/solve-field " + SOLVE_ARGS + " -D temp -N temp/ast.fits temp/src.fits") r = astResult.split('\n') coords = [0.0, 0.0] sCoordsSexa = ["00:00:00", "+00:00:00"] for line in r: if line.startswith("Field center"): if line.find("RA,Dec") > -1: sCoords = self.getPair(line.split('(')[2].split(')')[0]) coords = [ float(sCoords[0]), float(sCoords[1]) ] printInfo("Image center: %s %s" % (sCoords[0], sCoords[1])) else: sCoordsSexa = self.getPair(line.split('(')[2].split(')')[0]) coords = [ hexa2deg(sCoordSexa[0]) * 15.0, hexa2deg(sCoordSexa[1]) ] printInfo("Image center: %s %s" % (sCoordsSexa[0], sCoordsSexa[1])) elif line.startswith("Field size"): sFieldSize = self.getPair(line.split(':')[1].split('a')[0], 'x') printInfo("Image size: %s' x %s'" % (sFieldSize[0], sFieldSize[1])) return coords
def makeMasterBias(self, biasFolder, color): BIAS_PATTERN = "%s/%s*-%s.fits" % ( biasFolder, self.pplSetup['BIAS_FILE_PREFIX'], color) BIASLIST = glob.glob(BIAS_PATTERN) BIASLIST.sort() masterBiasFile = "%s/%s-%s.fits" % ( biasFolder, self.pplSetup['MASTER_BIAS_FILE'], color) if len(BIASLIST) == 0: return 1 print("%s -> %s" % (BIAS_PATTERN, masterBiasFile)) # Calibrated images: all the images have the same name but put into a separate directory ($TARGET): R_BIASLIST = list( map(lambda x: self.TEMPDIR + '/' + basename(x), BIASLIST)) # The calibration of the individual bias frames, followed by their combination into a single master image: invoke("ficalib -i %s %s %s -o %s" % (' '.join(BIASLIST), self.COMMON_ARGS, self.imSizeArg(BIASLIST[0]), ' '.join(R_BIASLIST))) invoke("ficombine %s --mode median -o %s" % (' '.join(R_BIASLIST), masterBiasFile)) # cleanup: remove temp files for f in R_BIASLIST: os.remove(f) return 0
def cleanFolder(self, subfolder, filePattern='*'): folderPattern = '*' + self.opt['baseFolder'] + '*/' + subfolder removePattern = folderPattern + '/' + filePattern fs = glob(removePattern) if len(fs) > 0: printInfo("Cleaning folders: %s" % (folderPattern)) for f in fs: invoke("rm -f %s" % (f)) else: print("No %s files in folders %s" % (filePattern, folderPattern))
def makeMasterDark(self, darkFolder, biasFolder, color): # Names of the individual files storing the raw bias, dark, flat and object frames: DARK_PATTERN = "%s/%s*-%s.fits" % ( darkFolder, self.pplSetup['DARK_FILE_PREFIX'], color) DARKLIST = glob.glob(DARK_PATTERN) DARKLIST.sort() masterDarkFile = "%s/%s-%s.fits" % ( darkFolder, self.pplSetup['MASTER_DARK_FILE'], color) masterBiasFile = "%s/%s-%s.fits" % ( biasFolder, self.pplSetup['MASTER_BIAS_FILE'], color) if len(DARKLIST) == 0: return 1 print("%s -> %s" % (DARK_PATTERN, masterDarkFile)) # Calibrated images: all the images have the same name but put into a separate directory ($TARGET): R_DARKLIST = list( map(lambda x: self.TEMPDIR + '/' + basename(x), DARKLIST)) # The calibration of the individual bias frames, followed by their combination into a single master image: invoke( "ficalib -i %s %s %s -o %s --input-master-bias %s" % (' '.join(DARKLIST), self.COMMON_ARGS, self.imSizeArg( DARKLIST[0]), ' '.join(R_DARKLIST), masterBiasFile)) invoke("ficombine %s --mode median -o %s" % (' '.join(R_DARKLIST), masterDarkFile)) # Calculate average ccd temperature from .cr2 files, and set it into the master dark tsum = 0 count = 0 for f in DARKLIST: hdr = getFitsHeader(f, 'CCD-TEMP') if hdr: ccdtemp = int() tsum += ccdtemp count += 1 if count > 0: AVGTEMP = (tsum + (count / 2)) / count print("average dark temperature: %d C" % (AVGTEMP)) setFitsHeaders( masterDarkFile, {'CCD-TEMP': ("%d." % (AVGTEMP), "CCD Temperature (Celsius)")}) # cleanup: remove temp files for f in R_DARKLIST: os.remove(f) return 0
def invoked(self, cmd): if self.opt['debug']: printDebug(cmd) result = invoke(cmd) if result.startswith('ERROR:'): printError(result[len('ERROR: '):]) elif self.opt['debug']: printDebug(result) return result
def makeMasterFlat(self, flatfolder, biasFolder, darkFolder, color): # Names of the individual files storing the raw bias, dark, flat and object frames: FLAT_PATTERN = "%s/%s*-%s.fits" % ( flatfolder, self.pplSetup['FLAT_FILE_PREFIX'], color) FLATLIST = glob.glob(FLAT_PATTERN) FLATLIST.sort() masterFlatFile = "%s/%s-%s.fits" % ( flatfolder, self.pplSetup['MASTER_FLAT_FILE'], color) masterDarkFile = "%s/%s-%s.fits" % ( darkFolder, self.pplSetup['MASTER_DARK_FILE'], color) masterBiasFile = "%s/%s-%s.fits" % ( biasFolder, self.pplSetup['MASTER_BIAS_FILE'], color) if len(FLATLIST) == 0: return 1 print("%s -> %s" % (FLAT_PATTERN, masterFlatFile)) # Calibrated images: all the images have the same name but put into a separate directory ($TARGET): R_FLATLIST = list( map(lambda x: self.TEMPDIR + '/' + basename(x), FLATLIST)) # The calibration of the individual flat frames, followed by their combination into a single master image: invoke( "ficalib -i %s %s %s --post-scale 20000 -o %s --input-master-bias %s --input-master-dark %s" % (' '.join(FLATLIST), self.COMMON_ARGS, self.imSizeArg(FLATLIST[0]), ' '.join(R_FLATLIST), masterBiasFile, masterDarkFile)) invoke("ficombine %s --mode median -o %s" % (' '.join(R_FLATLIST), masterFlatFile)) # remove temp files for f in R_FLATLIST: os.remove(f) return 0
def raw2fitsFile(self, rawfile, color): FITS_NAME = "%s-%s.fits" % (rawfile[:rawfile.rfind('.')], color) if self.opt['overwrite'] and exists(FITS_NAME): os.remove(FITS_NAME) if not exists(FITS_NAME): print("%s -> %s" % (rawfile, FITS_NAME)) # convert raw image to fits # TODO: use invoke, parse options with ' or " correctly, or use preparsed options os.system( "rawtran -c %s -o %s -B 16 -C '-4 -D -t 0' -X '-q 3 -w' %s" % (color, FITS_NAME, rawfile)) # read image temperature from raw file exif = invoke("exiftool -s -g %s" % (rawfile)) IMAGETEMP = None for line in exif.split('\n'): if line.startswith('CameraTemperature'): IMAGETEMP = line.split(':')[1].strip() break if IMAGETEMP: # write image temperature to fits file setFitsHeaders( FITS_NAME, {'CCD-TEMP': (IMAGETEMP, 'CCD Temperature (Celsius)')}) # convert observation time from local time to UT if self.opt['imageTime'] == 'LT': IMAGE_DATE = getFitsHeader(FITS_NAME, 'DATE-OBS') IMAGE_DATE_UTC = self.lt2ut(IMAGE_DATE) setFitsHeaders( FITS_NAME, { 'DATE-OBS': IMAGE_DATE_UTC, 'DATE-IMG': (IMAGE_DATE, 'Original image date (in local time)') }) else: print("%s file already exists." % (FITS_NAME))
def matchCatalogsByGrmatchPoints(self, refCatFile, pmCatFile, outFile): ''' Match reference catalog with sextractor's .cat file by frame xy points ''' # 1. convert refCat to fits format refFitsFile = refCatFile + '.fits' table = Table.read(refCatFile, format='ascii') if not exists(refFitsFile): table.write(refFitsFile) # 2. calculate ref objects' frame xy points wcsFile = pmCatFile.replace('.cat', '.wcs') axyFile = pmCatFile.replace('.cat', '.ref.axy') invoke("wcs-rd2xy -w %s -i %s -o %s -R RA_DEG -D DEC_DEG" % (wcsFile, refFitsFile, axyFile)) # -f option need argument remove(refFitsFile) # 3. merge frame xy point to refCat tlen = len(table) table['X'] = [0.0] * tlen table['Y'] = [0.0] * tlen table['ID'] = [0] * tlen table['ROLE_'] = ['AA'] * tlen f = fits.open(axyFile) d = f[1].data for j in range(tlen): x, y = d[j] table[j]['X'] = x table[j]['Y'] = y # 4. match refCat with sextractor's cat by frame xy points idFile = pmCatFile + ".idmatch" result = invoke( "grmatch -r %s -i %s --match-coord --col-ref 4,6 --col-inp 14,15 --output-id %s --col-ref-id 1 --col-inp-id 1" % (refCatFile, pmCatFile, idFile)) # get image size astFile = pmCatFile.replace('.cat', '.ast.fits') im_x, im_y = self.readFrameSize(astFile) idTable = Table.read(idFile, format='ascii') pmTable = Table.read(pmCatFile, format='ascii') hmgs = self.hmg(pmTable) print("Instumental HMG: HMG_ISOCORR = %8.4f, HMG_BEST = %8.4f" % (hmgs[0], hmgs[1])) for j in range(tlen): onFrameStatus = self.determineOnFrameStatus( table[j]['X'], table[j]['Y'], im_x, im_y) matched = False for k in range(len(idTable)): if table[j]['AUID'] == idTable[k][0]: table[j]['ID'] = int(idTable[k][1]) matched = True break pmid = int(table[j]['ID']) d = -1.0 if id != 0: pmrow = pmTable[pmid - 1] dx = pmrow['XWIN_IMAGE'] - table[j]['X'] dy = pmrow['YWIN_IMAGE'] - table[j]['Y'] d = sqrt(dx * dx + dy * dy) if onFrameStatus == '' and matched: # print('AUID: %s, ID:%d, d:%f, OK, on-frame and mathed' % (table[j]['AUID'], pmid, d)) if d > 2.0: print('AUID: %s, ID:%d, d:%f, OK, on-frame and mathed' % (table[j]['AUID'], pmid, d)) print(' and too large distance') table[j]['ROLE_'] = table[j]['ROLE'] + 'F' if table[j]['ROLE'] == 'V' and float( pmrow['MAG_BEST']) > hmgs[1]: if d <= 2.0: print('AUID: %s, ID:%d, OK, on-frame and mathed' % (table[j]['AUID'], pmid)) print(' and under limit, mi:%7.3f, hmg:%7.3f' % (float(pmrow['MAG_BEST']), hmgs[1])) table[j]['ROLE_'] = table[j]['ROLE'] + 'F' elif d <= 2.0: table[j]['ROLE_'] = table[j]['ROLE'] elif onFrameStatus == 'B' and matched: table[j]['ROLE_'] = table[j]['ROLE'] + 'B' print('AUID: %s, ID:%d, d:%f, OK, on-frame-border and mathed' % (table[j]['AUID'], pmid, d)) if d > 2.0: print(' and too large distance') table[j]['ROLE_'] = table[j]['ROLE'] + 'F' if table[j]['ROLE'] == 'VB' and float( pmrow['MAG_BEST']) > hmgs[1]: print(' and under limit, mi:%7.3f, hmg:%7.3f' % (float(pmrow['MAG_BEST']), hmgs[1])) table[j]['ROLE_'] = table[j]['ROLE'] + 'F' elif onFrameStatus == 'O' and matched: table[j]['ROLE_'] = table[j]['ROLE'] + 'O' print( 'AUID: %s, ID:%d, d:%f, BAD-MATCH, out-of-frame and mathed' % (table[j]['AUID'], pmid, d)) elif onFrameStatus == '' and not matched: table[j]['ROLE_'] = table[j]['ROLE'] + 'F' print('AUID: %s, FAINTER, on-frame and not mathed' % (table[j]['AUID'])) print(' and under limit, hmg:%7.3f' % (hmgs[1])) elif onFrameStatus == 'B' and not matched: table[j]['ROLE_'] = table[j]['ROLE'] + 'O' print( 'AUID: %s, FAINTER-ON-BORDER, on-frame-border and not mathed' % (table[j]['AUID'])) elif onFrameStatus == 'O' and not matched: table[j]['ROLE_'] = table[j]['ROLE'] + 'O' print('AUID: %s, OK, out-of-frame and not mathed' % (table[j]['AUID'])) # save result self.dumpResult(table, pmTable, outFile, hmgs)
def photometry(self, seqFolder, photFolder, refcatFileName, color): # Names of the sequence/combined files: SEQLIST = glob(seqFolder + '/' + self.pplSetup['SEQ_FILE_PREFIX'] + '*-' + color + '.fits') SEQLIST.sort() if len(SEQLIST) == 0: SEQLIST = glob(seqFolder + '/Combined-' + color + '.fits') if len(SEQLIST) == 0: printWarning("No files for photometry in folder %s" % (seqFolder)) return False for f in SEQLIST: print("photometry of %s" % (f)) AST_FILE = photFolder + '/' + basename(f).replace( '.fits', '.ast.fits') PMCAT_FILE = photFolder + '/' + basename(f).replace( '.fits', '.cat') printInfo("Make astrometry for %s" % (f)) if not exists(AST_FILE) or self.opt['overwrite']: print("%s/solve-field %s -D %s -N %s %s" % (self.pplSetup['AST_BIN_FOLDER'], self.SOLVE_ARGS, photFolder, AST_FILE, f)) invoke("%s/solve-field %s -D %s -N %s %s" % (self.pplSetup['AST_BIN_FOLDER'], self.SOLVE_ARGS, photFolder, AST_FILE, f)) fsolved = PMCAT_FILE.replace('.cat', '.solved') if not exists(fsolved): printError("Astrometry of %s failed." % (fsolved)) break else: print("astrometry file %s already exists." % (AST_FILE)) printInfo("Make photometry for %s" % (f)) if not exists(PMCAT_FILE) or self.opt['overwrite']: invoke( "sextractor %s -c %s -CATALOG_NAME %s -CATALOG_TYPE ASCII_HEAD" % (AST_FILE, self.SEX_CFG, PMCAT_FILE)) else: print("photometry file %s already exists." % (PMCAT_FILE)) PMCAT_FILE_FLT = PMCAT_FILE + ".cat" printInfo("Filtering result catalog to %s" % (PMCAT_FILE_FLT)) if not exists(PMCAT_FILE_FLT) or self.opt['overwrite']: opt = { 'ref': refcatFileName, 'out': PMCAT_FILE_FLT, 'color': color, 'files': [PMCAT_FILE], } matcher = CatalogMatcher(opt) matcher.process() else: print("filtered photometry file %s already exists." % (PMCAT_FILE_FLT)) return True
def removeFolder(self, subfolder): folderPattern = '*' + self.opt['baseFolder'] + '*/' + subfolder fs = glob(folderPattern) printInfo("Removing folders: %s" % (folderPattern)) for f in fs: invoke("rmdir %s" % (f))