def test_L0_defaults(): # Confirm that the output is the same when the default settings are explicitly set defaults = sun.L0('1992-Oct-13') explicit = sun.L0('1992-Oct-13', light_travel_time_correction=True, aberration_correction=False, nearest_point=True) assert defaults == explicit
def test_L0_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': 326.989970, '2013-02-01': 278.789894, '2013-03-01': 270.072186, '2013-04-01': 221.440599, '2013-05-01': 185.306476, '2013-06-01': 135.303097, '2013-07-01': 98.221806, # NOQA '2013-08-01': 48.035951, # NOQA '2013-09-01': 358.289921, '2013-10-01': 322.226009, '2013-11-01': 273.315206, '2013-12-01': 237.836959 } sun_L0 = sun.L0(Time(list(jpl_values.keys()), scale='tt'), light_travel_time_correction=True, aberration_correction=False, nearest_point=True) assert_longitude_allclose(sun_L0, list(jpl_values.values()) * u.deg, atol=0.01 * u.arcsec)
def test_hgc_self_observer(): # Test specifying observer='self' for HGC obstime = Time('2001-01-01') hgc = HeliographicCarrington(10*u.deg, 20*u.deg, 3*u.AU, observer='self', obstime=obstime) # Transform to HGS (i.e., observer='self' in the source frame) hgs = hgc.transform_to(HeliographicStonyhurst(obstime=obstime)) # Manually calculate the post-transformation longitude lon = sun.L0(obstime, light_travel_time_correction=False, nearest_point=False, aberration_correction=False) lon += (hgc.radius - _RSUN) / speed_of_light * sidereal_rotation_rate assert_quantity_allclose(Longitude(hgs.lon + lon), hgc.lon) assert_quantity_allclose(hgs.lat, hgc.lat) assert_quantity_allclose(hgs.radius, hgc.radius) # Transform back to HGC (i.e., observer='self' in the destination frame) hgc_loop = hgs.transform_to(hgc.replicate_without_data()) assert_quantity_allclose(hgc_loop.lon, hgc.lon) assert_quantity_allclose(hgc_loop.lat, hgc.lat) assert_quantity_allclose(hgc_loop.radius, hgc.radius)
def test_hgs_hgc_roundtrip(): obstime = "2011-01-01" hgsin = HeliographicStonyhurst(lat=10*u.deg, lon=20*u.deg, obstime=obstime) hgcout = hgsin.transform_to(HeliographicCarrington(obstime=obstime)) assert_quantity_allclose(hgsin.lat, hgcout.lat) assert_quantity_allclose(hgsin.lon + sun.L0(obstime), hgcout.lon) hgsout = hgcout.transform_to(HeliographicStonyhurst(obstime=obstime)) assert_quantity_allclose(hgsout.lat, hgsin.lat) assert_quantity_allclose(hgsout.lon, hgsin.lon)
def test_L0_array_time(): # Validate against published values from the Astronomical Almanac (2013) sun_L0 = sun.L0( Time([ '2013-01-01', '2013-02-01', '2013-03-01', '2013-04-01', '2013-05-01', '2013-06-01', '2013-07-01', '2013-08-01', '2013-09-01', '2013-10-01', '2013-11-01', '2013-12-01' ], scale='tt')) assert_quantity_allclose( sun_L0, [ 326.98, 278.78, 270.07, 221.44, 185.30, 135.30, 98.22, 48.03, 358.28, 322.22, 273.31, 237.83 ] * u.deg, atol=5e-3 * u.deg)
def test_L0_astronomical_almanac(): # Validate against published values from the Astronomical Almanac (2013) aa_values = {'2013-01-01': 326.98, '2013-02-01': 278.78, '2013-03-01': 270.07, '2013-04-01': 221.44, '2013-05-01': 185.30, '2013-06-01': 135.30, '2013-07-01': 98.22, # NOQA '2013-08-01': 48.03, # NOQA '2013-09-01': 358.28, '2013-10-01': 322.22, '2013-11-01': 273.31, '2013-12-01': 237.83} sun_L0 = sun.L0(Time(list(aa_values.keys()), scale='tt'), light_travel_time_correction=True, aberration_correction=True, nearest_point=False) assert_longitude_allclose(sun_L0, list(aa_values.values()) * u.deg, atol=5e-3*u.deg)
def hmi2pfsspy(dt, rss=2.5, nr=60, ret_magnetogram=False, data_dir=DefaultPath): #Input : dt (datetime object), rss (source surface radius in Rs) YYYYMMDD = f'{dt.year}{dt.month:02d}{dt.day:02d}' filepath = glob.glob( f'{data_dir}/hmi.mrdailysynframe_small_720s.{YYYYMMDD}*.fits')[0] stdout.write(f"Read in {filepath}\r") hmi_fits = fits.open(filepath)[0] hmi_fits.header['CUNIT2'] = 'degree' for card in ['HGLN_OBS', 'CRDER1', 'CRDER2', 'CSYSER1', 'CSYSER2']: hmi_fits.header[card] = 0 hmi_map = sunpy.map.Map(hmi_fits.data, hmi_fits.header) hmi_map.meta['CRVAL1'] = 120 + sun.L0(time=hmi_map.meta['T_OBS']).value br_hmi = extract_br(hmi_map) if ret_magnetogram: return br_hmi peri_input = pfsspy.Input(br_hmi, nr, rss, dtime=dt) peri_output = pfsspy.pfss(peri_input) return peri_output
def test_L0(): # Validate against a published value from Astronomical Algorithms (Meeus 1998, p.191) assert_quantity_allclose(sun.L0('1992-Oct-13'), 238.63 * u.deg, atol=2e-2 * u.deg)
def test_L0_array_time(): # Validate against published values from the Astronomical Almanac (2013) sun_L0 = sun.L0(Time(['2013-04-01', '2013-12-01'], scale='tt')) assert_quantity_allclose(sun_L0[0], 221.44 * u.deg, atol=5e-3 * u.deg) assert_quantity_allclose(sun_L0[1], 237.83 * u.deg, atol=5e-3 * u.deg)
def test_L0_sunspice(): # Validate against values from SunSPICE (including calling CSPICE functions) # With the aberration correction for observer motion (specify 'LT+S') # # IDL> load_sunspice_gen # IDL> cspice_str2et, '2013-01-01', et # IDL> cspice_subpnt, 'Intercept/Ellipsoid', 'Sun', et, 'IAU_Sun', 'LT+S', 'Earth', spoint1, trgepc1, srfvec1 # IDL> cspice_reclat, spoint1, spcrad1, spclon1, spclat1 # IDL> print, spclon1 * cspice_dpr() # -33.025998 values1 = { '2013-01-01': -33.025998, '2013-02-01': -81.226108, '2013-03-01': -89.943817, '2013-04-01': -138.57536, '2013-05-01': -174.70941, '2013-06-01': +135.28726, '2013-07-01': +98.205970, '2013-08-01': +48.020071, '2013-09-01': -1.7260099, '2013-10-01': -37.789945, '2013-11-01': -86.700744, '2013-12-01': -122.17899 } sun_L0 = sun.L0(Time(list(values1.keys()), scale='utc'), light_travel_time_correction=True, aberration_correction=True, nearest_point=True) assert_longitude_allclose(sun_L0, list(values1.values()) * u.deg, atol=0.3 * u.arcsec) # Without the aberration correction for observer motion (specify 'LT') # # IDL> cspice_subpnt, 'Intercept/Ellipsoid', 'Sun', et, 'IAU_Sun', 'LT', 'Earth', spoint2, trgepc2, srfvec2 # IDL> cspice_reclat, spoint2, spcrad2, spclon2, spclat2 # IDL> print, spclon2 * cspice_dpr() # -33.020271 values2 = { '2013-01-01': -33.020271, '2013-02-01': -81.220344, '2013-03-01': -89.938057, '2013-04-01': -138.56966, '2013-05-01': -174.70380, # '2013-06-01': 135.29281, # skipping due to low precision in comparison '2013-07-01': +98.211514, '2013-08-01': +48.025667, '2013-09-01': -1.7203500, '2013-10-01': -37.784252, '2013-11-01': -86.695047, '2013-12-01': -122.17329 } sun_L0 = sun.L0(Time(list(values2.keys()), scale='utc'), light_travel_time_correction=True, aberration_correction=False, nearest_point=True) assert_longitude_allclose(sun_L0, list(values2.values()) * u.deg, atol=0.01 * u.arcsec) # Without any corrections (do a straight conversion from 'HEQ' to 'Carrington') # # IDL> coord = [1.d, 0.d, 10.d] # IDL> convert_sunspice_lonlat, '2013-01-01', coord, 'HEQ', 'Carrington', /au, /degrees # IDL> print, coord # 1.0000000 326.89956 10.000000 values3 = { '2013-01-01': 326.89956, '2013-02-01': 278.69932, '2013-03-01': 269.98115, '2013-04-01': 221.34886, '2013-05-01': 185.21404, '2013-06-01': 135.21012, '2013-07-01': 98.128607, '2013-08-01': 47.942897, '2013-09-01': 358.19735, '2013-10-01': 322.13410, '2013-11-01': 273.22402, '2013-12-01': 237.74631 } sun_L0 = sun.L0(Time(list(values3.keys()), scale='utc'), light_travel_time_correction=False, aberration_correction=False, nearest_point=True) assert_longitude_allclose(sun_L0, list(values3.values()) * u.deg, atol=0.02 * u.arcsec)
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