def test_B0_sunspice(): # Validate against values from SunSPICE (including calling CSPICE functions) # Without the aberration correction for observer motion (specify 'LT') # # IDL> load_sunspice_gen # IDL> cspice_str2et, '2013-01-01', et # IDL> cspice_subpnt, 'Intercept/Ellipsoid', 'Sun', et, 'IAU_Sun', 'LT', 'Earth', spoint, trgepc, srfvec # IDL> print, spclat * cspice_dpr() # -3.0347784 jpl_values = { '2013-01-01': -3.0347784, '2013-02-01': -6.0319658, '2013-03-01': -7.2199937, '2013-04-01': -6.5430498, '2013-05-01': -4.1679382, '2013-06-01': -0.66371004, '2013-07-01': +2.8731155, '2013-08-01': +5.7847503, '2013-09-01': +7.1945709, '2013-10-01': +6.7198381, '2013-11-01': +4.3789008, '2013-12-01': +0.88096965 } sun_B0 = sun.B0(Time(list(jpl_values.keys()), scale='utc')) assert_quantity_allclose(sun_B0, list(jpl_values.values()) * u.deg, atol=0.005 * u.arcsec, rtol=0)
def test_B0_jpl_horizons(): # Validate against values from JPL Horizons, which does not apply the aberration correction # for observer motion. # https://ssd.jpl.nasa.gov/horizons_batch.cgi?batch=1&TABLE_TYPE=OBSERVER&OBJ_DATA=NO&QUANTITIES=%2714%27&COMMAND=%22Sun%22&CENTER=%27Geocentric%27&START_TIME=%222013-01-01+TT%22&STOP_TIME=%222013-12-31%22&STEP_SIZE=%221d%22 jpl_values = {'2013-01-01': -3.034687, '2013-02-01': -6.031910, '2013-03-01': -7.219984, '2013-04-01': -6.543092, '2013-05-01': -4.168016, '2013-06-01': -0.663804, '2013-07-01': +2.873030, '2013-08-01': +5.784693, '2013-09-01': +7.194559, '2013-10-01': +6.719875, '2013-11-01': +4.378979, '2013-12-01': +0.881068} sun_B0 = sun.B0(Time(list(jpl_values.keys()), scale='tt')) assert_quantity_allclose(sun_B0, list(jpl_values.values()) * u.deg, atol=0.01*u.arcsec, rtol=0)
def test_B0_array_time(): # Validate against published values from the Astronomical Almanac (2013) sun_B0 = sun.B0(Time(['2013-04-01', '2013-12-01'], scale='tt')) assert_quantity_allclose(sun_B0[0], -6.54 * u.deg, atol=5e-3 * u.deg) assert_quantity_allclose(sun_B0[1], 0.88 * u.deg, atol=5e-3 * u.deg)
def test_B0(): # Validate against a published value from Astronomical Algorithms (Meeus 1998, p.191) assert_quantity_allclose(sun.B0('1992-Oct-13'), 5.99 * u.deg, atol=5e-3 * u.deg)
def prepData(files, base_dir, prefix, custom_keywords={}, plot=False): diffs = {'center_x': [], 'center_y': [], 'radius': [], 'scale': []} os.makedirs(os.path.join(base_dir, 'level1'), exist_ok=True) os.makedirs(os.path.join(base_dir, 'level1_5'), exist_ok=True) with warnings.catch_warnings(): warnings.simplefilter("ignore") for file in tqdm(files): try: # load existing file hdul = fits.open(file) hdu = hdul[0] hdu.verify('fix') d, h = hdu.data, hdu.header # set custom keywords h.update(custom_keywords) # evaluate center and radius imsave("demo.jpg", d) myCmd = os.popen( '/home/rja/PythonProjects/SpringProject/spring/limbcenter/sunlimb demo.jpg' ).read() center_x, center_y, radius, d_radius = map( float, myCmd.splitlines()) if "EXPTIME" in h: h['EXP_TIME'] = h['EXPTIME'] del h['EXPTIME'] if 'TIME-OBS' in h: obs_date = datetime.strptime( h['DATE-OBS'] + 'T' + h['TIME-OBS'], "%m/%d/1%yT%H:%M:%S") h['DATE-OBS'] = obs_date.isoformat() del h["TIME-OBS"] if 'TIME' in h: obs_date = datetime.strptime( h['DATE-OBS'] + 'T' + h['TIME'], "%d/%m/%YT%H:%M:%S") h['DATE-OBS'] = obs_date.isoformat() del h["TIME"] obs_time = parse(h["DATE-OBS"]) rsun = angular_radius(obs_time) b0_angle = sun.B0(obs_time) l0 = sun.L0(obs_time) p_angle = sun.P(obs_time) filename = "%s_%s_fi_%s.fits" % ( prefix, h["OBS_TYPE"].lower(), obs_time.strftime("%Y%m%d_%H%M%S")) # prepare existing header information if "ANGLE" not in h: h["ANGLE"] = p_angle.value scale = rsun / (radius * u.pix) coord = SkyCoord(0 * u.arcsec, 0 * u.arcsec, obstime=obs_time, observer='earth', frame=frames.Helioprojective) # create WCS header info header = header_helper.make_fitswcs_header( d, coord, rotation_angle=h["ANGLE"] * u.deg, reference_pixel=u.Quantity([center_x, center_y] * u.pixel), scale=u.Quantity([scale, scale]), instrument=h["INSTRUME"], telescope=h["TELESCOP"], observatory=h["OBSVTRY"], exposure=h["EXP_TIME"] * u.ms, wavelength=h["WAVELNTH"] * u.angstrom) header["KEYCOMMENTS"] = { "EXPTIME": "[s] exposure time in seconds", "DATE": "file creation date (YYYY-MM-DDThh:mm:ss UT)", "DATE-OBS": "date of observation", "WAVELNTH": "[Angstrom] wavelength", "BANDPASS": "******", "WAVEMIN": "[Angstrom] minimum wavelength", "WAVEMAX": "[Angstrom] maximum wavelength", "BZERO": "offset data range to that of unsigned short", "CDELT1": "[arcsec/pix]", "CDELT2": "[arcsec/pix]", "SOLAR_R": "[pix]", "DSUN_OBS": "[m]", "RSUN_REF": "[m]", "RSUN_ARC": "[%s]" % rsun.unit, "ANGLE": "[deg]", "SOLAR_P": "[%s]" % p_angle.unit, "SOLAR_L0": "[%s]" % l0.unit, "SOLAR_B0": "[%s]" % b0_angle.unit, 'SIMPLE': 'file does conform to FITS standard', 'BITPIX': 'number of bits per data pixel', 'CUNIT1': '[arcsec]', 'CUNIT2': '[arcsec]', 'CRVAL1': 'coordinate system value at reference pixel', 'CRVAL2': 'coordinate system value at reference pixel', 'CTYPE1': 'name of the coordinate axis', 'CTYPE2': 'name of the coordinate axis', 'INSTRUME': 'name of instrument', 'TELESCOP': 'name of telescope', 'OBSVTRY': 'name of observatory', } # set constants and default values header["FILENAME"] = filename header["DATE"] = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") header["SOLAR_R"] = radius header["RSUN_ARC"] = rsun.value header["SOLAR_P"] = p_angle.value header["SOLAR_L0"] = l0.value header["SOLAR_B0"] = b0_angle.value header["DATAMIN"] = np.min(d) header["DATAMEAN"] = np.mean(d) header["DATAMAX"] = np.max(d) # copy existing keys for key, value in h.items(): if key not in header: header[key] = value # copy comments for key, value in zip(list(h.keys()), list(h.comments)): if key not in header["KEYCOMMENTS"]: header["KEYCOMMENTS"][key] = value # LEVEL 1 s_map = Map(d.astype(np.float32), header) level1_path = os.path.join(base_dir, 'level1', filename) h.add_history("unified FITS header") s_map.meta["HISTORY"] = h["HISTORY"] s_map.meta["LVL_NUM"] = "1.0" s_map = Map(s_map.data.astype(np.float32), s_map.meta) s_map.save(level1_path, overwrite=True) # LEVEL 1.5 scale = s_map.scale[0].value s_map = padScale(s_map) s_map = s_map.rotate( recenter=True, scale=scale, missing=s_map.min(), ) center = np.floor(s_map.meta['crpix1']) range_side = (center + np.array([-1, 1]) * 2048 / 2) * u.pix s_map = s_map.submap( u.Quantity([range_side[0], range_side[0]]), u.Quantity([range_side[1], range_side[1]])) level1_5_path = os.path.join(base_dir, 'level1_5', filename) h.add_history("recentered and derotated") s_map.meta["HISTORY"] = h["HISTORY"] s_map.meta["LVL_NUM"] = "1.5" s_map = Map(s_map.data.astype(np.float32), s_map.meta) s_map.save(level1_5_path, overwrite=True) if plot: s_map.plot() s_map.draw_grid() plt.savefig(level1_5_path.replace(".fits", ".jpg")) plt.close() # check header hdul = fits.open(level1_5_path) hdu = hdul[0] hdu.verify('exception') # evaluate difference if 'center_x' in h and not isinstance(h["center_x"], str): diffs['center_x'].append( np.abs(h['center_x'] - header['crpix1'])) if 'center_y' in h and not isinstance(h["center_y"], str): diffs['center_y'].append( np.abs(h['center_y'] - header['crpix2'])) if 'SOLAR_R' in h and not isinstance(h["SOLAR_R"], str): diffs['radius'].append( np.abs(h['SOLAR_R'] - header['SOLAR_R'])) if 'cdelt1' in h and not isinstance(h["cdelt1"], str): diffs['scale'].append( np.abs(h['cdelt1'] - header['cdelt1'])) except Exception as ex: print("INVALID FILE", file) print("ERROR:", ex) return diffs