def saveImage(self, img, imgFileName): imsave(imgFileName, img) if self.opt['color'] == 'all': printInfo("Color image %s created." % (imgFileName)) else: printInfo("Monochrome %s image %s created." % (self.opt['color'], imgFileName))
def process_photometry(self, seqFolder, photFolder, title): printInfo("%s: Make photometry on sequence file(s)." % (title)) # Create the photometry dir, if not exists if not exists(photFolder): mkdir(photFolder) # Photometry reference file: sf = seqFolder basedir = sf.replace(self.pplSetup['SEQ_FOLDER_NAME'], '') PMREFS = glob(basedir + '/*.cat') if len(PMREFS) > 0 and exists(PMREFS[0]): PMREF = PMREFS[0] else: printError("No reference catalog file (.cat) in folder %s" % (basedir)) printInfo( "Use ppl-refcat command to create reference catalog for the object." ) return False for color in self.opt['color']: self.photometry(seqFolder, photFolder, PMREF, color) self.calculateMags(photFolder, self.opt['color']) # TODO: cleanup - delete light FITS files return True
def processFlat(self, flatFolder, biasFolder, darkFolder, title): printInfo(title + ": Convert flat RAW files to FITS.") self.raw2fits(flatFolder) printInfo(title + ": Create master dark file(s).") for color in self.opt['color']: self.makeMasterFlat(flatFolder, biasFolder, darkFolder, color)
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 processRegistration(self, calibFolder, seqFolder, title): printInfo(title + ": Register and stack calibrated light file(s).") # Create the sequence dir, if not exists if not exists(seqFolder): makedirs(seqFolder) self.REF = None for color in self.opt['color']: self.registrate(calibFolder, seqFolder, color)
def processCalibration(self, lightFolder, calibFolder, title): printInfo(title + ": Convert light RAW files to FITS.") self.raw2fits(lightFolder) printInfo(title + ": Create calibrated light file(s).") # Create dir for the calibrated images, if not exists if not exists(calibFolder): makedirs(calibFolder) for color in self.opt['color']: self.calibrate(lightFolder, calibFolder, color)
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 calculateMags(self, photFolder, colors): # Names of the sequence/combined files: color = colors[0] PHOTLIST = glob(photFolder + '/' + self.pplSetup['SEQ_FILE_PREFIX'] + '*-' + color + '.cat.cat') PHOTLIST.sort() if len(PHOTLIST) == 0: PHOTLIST = glob(photFolder + '/Combined-' + color + '.cat.cat') # print(PHOTLIST) if len(PHOTLIST) == 0: printWarning("No files for calculate magnitudes in folder %s" % (photFolder)) return False for f in PHOTLIST: inputFiles = [] for c in colors: inputFiles.append(f.replace('-' + color, '-' + c)) printInfo("Calculate real magnitudes to %s" % (f.replace('-' + color, '-*') + '.pm')) pmopt = { 'out': None, 'comp': None, 'color': colors, 'method': self.opt['method'], 'loadCoeffs': self.opt['useStd'], 'useCoeffs': self.opt['useStd'] or self.opt['adhocStd'], 'makeCoeffs': self.opt['makeStd'] or self.opt['adhocStd'], 'saveCoeffs': self.opt['makeStd'], 'showGraphs': self.opt['showGraphs'], 'observer': self.opt['nameCode'], 'files': inputFiles, } phot = Photometry(pmopt, self.pplSetup) phot.process()
def processBias(self, biasFolder, title): ex = self.mastersExist(biasFolder, self.pplSetup['MASTER_BIAS_FILE']) if self.opt['overwrite'] or not ex: printInfo(title + ": Convert bias RAW files to FITS.") self.raw2fits(biasFolder) printInfo(title + ": Create master bias file.") for color in self.opt['color']: self.makeMasterBias(biasFolder, color) else: printInfo(title + ": Master bias file(s) are already created.")
def processDark(self, darkFolder, biasFolder, title): ex = self.mastersExist(darkFolder, self.pplSetup['MASTER_DARK_FILE']) if self.opt['overwrite'] or not ex: printInfo(title + ": Convert dark RAW files to FITS.") self.raw2fits(darkFolder) printInfo(title + ": Create master dark file(s).") for color in self.opt['color']: self.makeMasterDark(darkFolder, biasFolder, color) else: printInfo(title + ": Master dark file(s) are already created.")
def execute(self): ########################## # step 0. setup photometry ########################## self.pplSetup = loadPplSetup() seqFolders = discoverFolders(self.opt['baseFolder'], self.pplSetup['SEQ_FOLDER_NAME']) if len(seqFolders) == 0: printError('No sequence folder found in base folder %s' % (self.opt['baseFolder'])) exit(1) print("Sequence folders discovered:", seqFolders) # ## Common arguments (saturation level, image section & trimming, etc.): self.AST_CFG = self.pplSetup['CONFIG_FOLDER'] + "/astrometry.cfg" self.SEX_CFG = self.pplSetup['CONFIG_FOLDER'] + "/sex.cfg" # SOLVE_ARGS="-O --config $AST_CFG --use-sextractor --sextractor-path sextractor -i ${PHOTDIR}/scamp.cat -n ${PHOTDIR}/scamp.cfg -j ${PHOTDIR}/scamp.ref -r -y -p" self.SOLVE_ARGS = "-O --config %s --use-sextractor --sextractor-path sextractor -r -y -p" % ( self.AST_CFG) #################################### # step 1. do photometry for all file #################################### PMERROR = False requestedColors = self.opt['color'] requestedStd = self.opt['useStd'] for sf in seqFolders: baseFolder = sf.replace('/' + self.pplSetup['SEQ_FOLDER_NAME'], '') self.opt['color'] = requestedColors self.opt['useStd'] = requestedStd refcatAvailable = self.inspectRefCat(baseFolder) if not refcatAvailable: printError( 'Reference catalog is not usable for photometry ; skip folder %s' % (sf)) continue pf = sf.replace(self.pplSetup['SEQ_FOLDER_NAME'], self.pplSetup['PHOT_FOLDER_NAME']) success = self.process_photometry(sf, pf, "PHOTOMETRY") if not success: PMERROR = True break ######################################## # step 2. create report from all results ######################################## if not PMERROR: if self.opt['baseFolder'] != None: PM_FILES = glob('*' + self.opt['baseFolder'] + '*/' + self.pplSetup['PHOT_FOLDER_NAME'] + '/*.pm') BASE_FOLDERS = glob('*' + self.opt['baseFolder'] + '*') REPORT_FOLDER = BASE_FOLDERS[0] else: PM_FILES = glob(self.pplSetup['PHOT_FOLDER_NAME'] + '/*.pm') REPORT_FOLDER = getcwd() printInfo("Create report into %s folder." % (REPORT_FOLDER)) opt = { 'out': REPORT_FOLDER, # output folder 'rpt': 'aavso', # report format, default: aavso extended 'name': self.opt['nameCode'], # observer name code 'method': self. opt['method'], # mg calculation method, comp - single com star, gcx/lfit - ensemble 'files': PM_FILES, } proc = ReportProcessor(opt) proc.process() print() print(Blue + "Photometry is ready." + Color_Off)
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 execute(self): self.ppl = loadPplSetup() if self.opt['mgLimit'] == None: ml = float(self.ppl['DEF_FIELD_STAR_MG_LIMIT']) self.opt['mgLimit'] = ml if ml > 0.0 and ml < 25.0 else 17.0 if self.opt['image'] != None: coords = self.determineCoordsFromImage (self.opt['image']) self.opt['ra'] = coords[0] self.opt['dec'] = coords[1] outFileName = self.ppl['CONFIG_FOLDER'] if not outFileName.endswith('/'): outFileName += '/' outFileName += 'cat/' if not exists(outFileName): makedirs(outFileName) if self.opt['object'] != None: outFileName += self.opt['object'].lower().replace(' ', '_') + '.cat' elif self.opt['stdFieldName'] != None: outFileName += self.opt['stdFieldName'].lower().replace(' ', '_') + '.cat' else: s_ra = deg2hexa(self.opt['ra'] / 15.0) s_dec = deg2hexa(float(self.opt['dec'])) if not s_dec.startswith('+') and not s_dec.startswith('-'): s_dec = '+' + s_dec outFileName += s_ra.replace(':', '')[:4] + s_dec.replace(':', '')[:5] + '.cat' if not exists(outFileName) or self.opt['overwrite']: self.writeRecord('AUID', 'ROLE', 'RA', 'RA_DEG', 'DEC', 'DEC_DEG', 'MAG_B', 'ERR_B', 'MAG_V', 'ERR_V', 'MAG_R', 'ERR_R', 'LABEL') if self.opt['object'] != None: self.loadVspPhotometryData(self.opt['object'], fov = self.opt['field']) self.loadVsxCatalogData(self.opt['object'], fov = self.opt['field'], auidOnly = self.opt['auidOnly']) elif self.opt['stdFieldName'] != None: error = self.loadStdFieldData(self.opt['stdFieldName']) if not error: self.loadVsxCatalogData(None, ra = self.opt['ra'], dec = self.opt['dec'], fov = self.opt['field'], auidOnly = self.opt['auidOnly']) else: self.loadVspPhotometryData(None, ra = self.opt['ra'], dec = self.opt['dec'], fov = self.opt['field']) self.loadVsxCatalogData(None, ra = self.opt['ra'], dec = self.opt['dec'], fov = self.opt['field'], auidOnly = self.opt['auidOnly']) # collect field stars if self.opt['fieldStars']: if self.opt['object'] != None: target = self.opt['object'] else: target = SkyCoord(ra=self.opt['ra'], dec=self.opt['dec'], unit=(u.deg, u.deg), frame='icrs') self.loadFieldStars(target, self.opt['field'], self.opt['mgLimit']) # write cataglog to file outFile = open(outFileName, 'w') for s in self.cache: outFile.write(s + '\n') outFile.write('### chartid: ' + self.chartId + '\n') outFile.write('### fov: ' + str(self.opt['field']) + ' arcmin\n') outFile.close() printInfo("Reference catalog file %s created." % (outFileName)) else: printInfo("Reference catalog file %s is exists." % (outFileName)) if self.opt['folder']: # create link to refcat in given folder for f in glob(self.opt['folder'] + '*.cat'): remove(f) symlink(outFileName, self.opt['folder'] + 'ref.cat')
def loadStdFieldData(self, stdFieldName): saName = self.opt['stdFieldName'] configFolder = self.ppl["CONFIG_FOLDER"] if configFolder == None: configFolder = "$HOME/.pmlib" # load stdArea file saFieldsFile = configFolder + "/landolt_fields.txt" if not exists(saFieldsFile): printError("Landolt standard field catalog file %s not found" % (saFieldsFile)) return 'NoFile' saFields = Table.read(saFieldsFile, format = 'ascii') # find std area rows = list(filter(lambda r: r['FIELD_NAME'] == saName, saFields)) if len(rows) == 0: printError("No field name %s found in standard area file %s." % (saName, saFieldsFile)) return 'NoField' sa = rows[0] printInfo("StdArea: %s, Coords: %s %s, NumStars: %d, Comment: %s" % (saName, sa['RA_2000'], sa['DEC_2000'], sa['NS'], sa['COMMENT'])) self.opt['ra'] = hexa2deg(sa['RA_2000']) * 15.0 self.opt['dec'] = hexa2deg(sa['DEC_2000']) self.chartId = saName # load stdStars file saStarsFile = configFolder + "/landolt_stars.txt" if not exists(saStarsFile): printError("Landolt standard stars catalog file %s not found" % (saStarsFile)) return 'NoFile' saStars = Table.read(saStarsFile, format = 'ascii') # find std stars stars = list(filter(lambda r: r['FIELD_NAME'] == saName, saStars)) if len(stars) == 0: printError("No stars for standard field %s in standard area file %s." % (saName, saStarsFile)) return 'NoStars' # write stars to catalog file nrUnknown = 1 for star in stars: auid = '999-STD-%03d' % (nrUnknown) nrUnknown = nrUnknown + 1 role = "C" ra = star['RA_2000'] raDeg = "%10.8f" % (hexa2deg(ra) * 15.0) dec = star['DEC_2000'] decDeg = "%+10.8f" % (hexa2deg(dec)) mv = float(star['MAG_V']) ev = float(star['ERR_V']) magB = "%+6.4f" % (float(star['MAG_BV']) + mv) errB = "%+7.4f" % (max(ev, float(star['ERR_BV']))) magV = "%+6.4f" % (mv) errV = "%+7.4f" % (ev) magR = "%+6.4f" % (mv - float(star['MAG_VR'])) errR = "%+7.4f" % (max(ev, float(star['ERR_VR']))) label = saName + ":" + star['STAR'] self.writeRecord(auid, role, ra, raDeg, dec, decDeg, magB, errB, magV, errV, magR, errR, label) self.xmatchTable.add_row([auid, raDeg, decDeg, label]) print("%d standard star found for standard area %s" % (len(stars), saName)) return None
def execute(self): ########################## # step 0. setup photometry ########################## self.pplSetup = loadPplSetup() self.discoverFolders() if self.opt['masterFlat']: if not isdir(self.opt['masterFlat']): printError("Master-flat folder %s not exists." % (self.opt['masterFlat'])) exit(1) else: hasMaster = True for c in self.opt['color']: mfc = "%s/%s-%s.fits" % (self.opt['masterFlat'], self.pplSetup['MASTER_FLAT_FILE'], c) print(mfc) if not exists(mfc): printError( "No %s master-flat file in the directory %s" % (c, self.opt['masterFlat'])) hasMaster = False if hasMaster: self.FLAT_FOLDER = self.opt['masterFlat'] print("master-flat: " + self.opt['masterFlat']) else: exit(1) # create the temp dir, if not exists if not exists(self.TEMPDIR): makedirs(self.TEMPDIR) #################################### # step 1. create master bias frame #################################### if not self.opt['flatOnly']: self.processBias(self.BIAS_FOLDER, "BIAS") #################################### # step 2. create master dark frame #################################### self.processDark(self.DARK_FOLDER, self.BIAS_FOLDER, "DARK") if not self.opt['useMasterFlat']: # process flat bias, flat dark and flat, only if flat master is not exist ex = self.mastersExist(self.FLAT_FOLDER, self.pplSetup['MASTER_FLAT_FILE']) if self.opt['overwrite'] or not ex: ############################################################################ # step 3. create master flat bias frame, if it is differs from master bias ############################################################################ self.processBias(self.FLAT_BIAS_FOLDER, "FLAT BIAS") ############################################################################ # step 4. create master flat dark frame, if it is differs from mastre dark ############################################################################ self.processDark(self.FLAT_DARK_FOLDER, self.FLAT_BIAS_FOLDER, "FLAT DARK") ############################## # step 5. create master flat ############################## self.processFlat(self.FLAT_FOLDER, self.FLAT_BIAS_FOLDER, self.FLAT_DARK_FOLDER, "FLAT") else: printInfo("FLAT: Master flat file(s) are already created.") ################################## # step 6. calibrate light frames ################################## if not self.opt['flatOnly']: for lf in self.LIGHT_FOLDERS: cf = lf.replace(self.pplSetup['LIGHT_FOLDER_NAME'], self.pplSetup['CALIB_FOLDER_NAME']) self.processCalibration(lf, cf, "CALIBRATE") ############################################### # step 7. registrate and combine light frames ############################################### sf = lf.replace(self.pplSetup['LIGHT_FOLDER_NAME'], self.pplSetup['SEQ_FOLDER_NAME']) self.processRegistration(cf, sf, "REGISTRATE") print() print(Blue + "Calibration is ready." + Color_Off)
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))