def __init__(self, altitude, inclination, solarmodulation=None):
        self.Alt = altitude  # instrument altitude (km)
        self.magl = inclination  # orbit inclination (deg.)
        self.geomlat = inclination  # geomagnetic latitude (deg.) TODO
        # The inclination was used to approximate the average Magnetic Latitude
        """ solar modulation potential (MV): ~550 for solar minimum
                                            ~1100 for solar maximum
        """
        if solarmodulation is None:
            self.solmod = 650.
        else:
            self.solmod = solarmodulation

        EarthRadius = R_earth.to('km').value
        """ Average Geomagnetic cutoff in GV
        for a dipole approximations
        Equation 4 Smart et al. 2005
        doi:10.1016/j.asr.2004.09.015
        """
        R_E = R_earth.to('cm').value
        # g 01 term (in units of G) from IGRF-12 for 2015
        g10 = 29442 * 10**(-9) * 10**4  # G

        M = g10 * R_E * 300 / 10**9  # GV/cm2

        self.AvGeomagCutOff = (M / 4 * (1 + self.Alt / EarthRadius)**(-2.0) *
                               np.cos(np.deg2rad(self.geomlat))**4)

        AtmosphereHeight = 40  # km

        self.HorizonAngle = 90.0 + np.rad2deg(
            np.arccos(
                (EarthRadius + AtmosphereHeight) / (EarthRadius + self.Alt)))
Beispiel #2
0
def moon_distance(loc, t2, t3):
    # Get the distance to the moon via the umbra diameter estimate

    if isinstance(loc, type(u'')) or isinstance(loc, type('')):
        loc = EarthLocation.of_address(loc)

    # Location of Sun & Moon
    sun = get_sun(t2)
    moon = get_moon(t2, loc)

    # Umbra size, from time and location
    su = estimate_umbra(loc, t2, t3)

    # Constants in km
    re = R_earth.to(u.km).value
    ds = sun.distance.to(u.km).value
    rs = R_sun.to(u.km).value
    rm = 1738.1

    dm = (2 * rm - su) * ds / (2 * (rs - rm)) + re
    print(
        'Distance estimate: {:.7} km (Actual: {:.7}). Ratio: {:.2}. Difference: {:.7}'
        .format(dm, moon.distance, moon.distance / (dm * u.km),
                dm * u.km - moon.distance))
    # moon.distance is from surface, not center
    return dm, moon.distance.to(u.km).value + re
Beispiel #3
0
 def test_vallado61(self):
     alt_i = 191.34411  # km
     alt_f = 35781.34857  # km
     k = k_earth.to(units.km ** 3 / units.s ** 2).value
     R = R_earth.to(units.km).value
     expected_dv = 3.935224  # km/s
     expected_t_trans = 5.256713  # h
     r_i = R + alt_i
     r_f = R + alt_f
     dva, dvb, _, t_trans = hohmann(k, r_i, r_f)
     dv = abs(dva) + abs(dvb)
     assert_almost_equal(dv, expected_dv, decimal=2)
     assert_almost_equal(t_trans / 3600, expected_t_trans, decimal=2)
Beispiel #4
0
 def test_vallado62(self):
     alt_i = 191.34411  # km
     alt_b = 503873  # km
     alt_f = 376310.0  # km
     k = k_earth.to(units.km ** 3 / units.s ** 2).value
     R = R_earth.to(units.km).value
     expected_dv = 3.904057  # km/s
     expected_t_trans = 593.919803  # h
     r_i = R + alt_i
     r_b = R + alt_b
     r_f = R + alt_f
     dva, dvb, dvc, _, _, t_trans1, t_trans2 = bielliptic(k, r_i, r_b, r_f)
     dv = abs(dva) + abs(dvb) + abs(dvc)
     t_trans = t_trans1 + t_trans2
     assert_almost_equal(dv, expected_dv, decimal=2)
     assert_almost_equal(t_trans / 3600, expected_t_trans, decimal=0)
Beispiel #5
0
def get_umbra(loc, t2):
    # Get the real size of the umbra

    sun = get_sun(t2)
    moon = get_moon(t2, loc)
    sun_altaz = sun.transform_to(AltAz(obstime=t2, location=loc))

    # Constants in km
    re = R_earth.to(u.km).value
    ds = sun.distance.to(u.km).value
    rs = R_sun.to(u.km).value
    rm = 1738.1

    alpha = np.arcsin((rs - rm) / (ds - moon.distance.to(u.km).value))
    su = 2 * (rm / np.sin(alpha) -
              (moon.distance.to(u.km).value - re)) * np.tan(alpha)
    su / np.tan(sun_altaz.alt.to(u.rad))  # not 100% sure of this

    return su
Beispiel #6
0
        symbol : str, optional
            Symbol for the body, default to None.
        R : Quantity, optional
            Radius of the body, default to 0 km.

        """
        if not check_units((k, R), (u.m ** 3 / u.s ** 2, u.m)):
            raise u.UnitsError("Units must be consistent")

        self.k = k
        self.name = name
        self.symbol = symbol
        self.R = R

    def __str__(self):
        return u"{} ({})".format(self.name, self.symbol)

    def _repr_latex_(self):
        """Creates a LaTeX representation.

        Used by the IPython notebook.

        """
        return self.__str__()


Sun = Body(k=132712440018 * u.km ** 3 / u.s ** 2,
           name="Sun", symbol=u"\u2609")
Earth = Body(k=398600 * u.km ** 3 / u.s ** 2,
             name="Earth", symbol=u"\u2641", R=R_earth.to(u.km))
Beispiel #7
0
        self.k = k
        self.name = name
        self.symbol = symbol
        self.R = R

    @classmethod
    @u.quantity_input(k=u.km**3 / u.s**2, R=u.km)
    def from_parameters(cls, k, name, symbol, R):
        return cls(k, name, symbol, R)

    def __str__(self):
        return u"{0} ({1})".format(self.name, self.symbol)

    def _repr_latex_(self):
        """Creates a LaTeX representation.

        Used by the IPython notebook.

        """
        return self.__str__()


Sun = Body.from_parameters(k=132712440018 * u.km**3 / u.s**2,
                           name="Sun",
                           symbol=u"\u2609",
                           R=695700 * u.km)
Earth = Body.from_parameters(k=398600 * u.km**3 / u.s**2,
                             name="Earth",
                             symbol=u"\u2641",
                             R=R_earth.to(u.km))
Beispiel #8
0
def estimate_umbra(loc, t2, t3, verbose=False):
    # Estimate the size of the umbra from the contact times (not 100% sure on this yet)
    delta_t = t3 - t2

    # Location of Sun
    sun = get_sun(t2)
    sun_altaz = sun.transform_to(AltAz(obstime=t2, location=loc))

    # Umbra size, from time and location
    s_umbra = 2 * np.pi * R_earth * np.cos(loc.latitude.to(
        u.rad)) / u.day * delta_t
    s_umbra /= np.tan(sun_altaz.alt.to(
        u.rad))  # correction for altitude (correct?)
    su = s_umbra.to(u.km).value

    # Extra corrections for projection/location from central line
    # TODO: Need to check if this is the right approach
    df = get_path()
    df['sep'] = ang_sep(loc, df['clon'], df['clat']) * 2 * np.pi * R_earth.to(
        u.km).value / 360.
    ind = df[df['sep'] == min(df['sep'])].index[0]

    # Replace with finer version
    x2 = 41.
    x1 = 0.
    df_fine = pd.DataFrame(np.arange(x1, x2, 1), columns=['xval'])
    df_fine['clat'] = make_fine('clat', ind, df, x1=x1, x2=x2)
    df_fine['clon'] = make_fine('clon', ind, df, x1=x1, x2=x2)
    df_fine['width'] = make_fine('width', ind, df, x1=x1, x2=x2)

    # Get new best index
    df_fine['sep'] = ang_sep(loc, df_fine['clon'],
                             df_fine['clat']) * 2 * np.pi * R_earth.to(
                                 u.km).value / 360.
    ind = df_fine[df_fine['sep'] == min(df_fine['sep'])].index[0]
    df = df_fine

    # Get the angle
    factor = np.pi / 180
    lat1 = df.loc[ind, 'clat'] * factor
    lat2 = lat1
    dlon = (df.loc[ind, 'clon'] - df.loc[ind - 1, 'clon']) * factor
    theta1 = np.arctan2(
        np.sin(dlon) * np.cos(lat2),
        np.cos(lat1) * np.sin(lat2) -
        np.sin(lat1) * np.cos(lat2) * np.cos(dlon)) / factor
    lat2 = df.loc[ind - 1, 'clat'] * factor
    theta2 = np.arctan2(
        np.sin(dlon) * np.cos(lat2),
        np.cos(lat1) * np.sin(lat2) -
        np.sin(lat1) * np.cos(lat2) * np.cos(dlon)) / factor
    theta = abs(theta1 - theta2)

    # Modify the umbra size
    # TODO: This still needs more work as it doesn't give an approximately correct value
    ratio = 0.5 * df.loc[ind, 'width'] / (0.5 * df.loc[ind, 'width'] -
                                          df.loc[ind, 'sep'])
    su2 = su * ratio / np.cos(theta * factor)

    if verbose:
        print(df.loc[ind, ['clon', 'clat', 'width', 'sep']])
        print('Angle: {} (Cosine: {})'.format(theta, np.cos(theta * factor)))
        print('Ratio: {}'.format(ratio))
        print('{} -> {}'.format(su, su2))

    return su2
    def get_observatory_info(self, time_delta=None):
        """Compute the lat/lon and altitude of HST.

        Using the expstart and expend, generate a series MJD dates that correspond
        to 1 minute intervals. Calculate the lat/lon and altitude at each
        time step.

        """

        altitude_list = []
        lat_list = []
        lon_list = []

        # Break up the exposure into one minute intervals
        if time_delta is None:
            time_delta = self.metadata['expend'] - self.metadata['expstart']
            num_intervals = 2*int(time_delta.to('minute').value)
            expend = self.metadata['expend'].mjd
        else:
            expend= self.metadata['expstart'].mjd + time_delta/86400.0
            num_intervals = int(np.round(time_delta/60))

        # If the number of one minute intervals is less than 2, set the number
        # of intervals to 5 (arbitrarily chosen)
        if num_intervals < 2:
            num_intervals = 5
        # Generate MJD dates correspond to these one minute intervals
        time_intervals = np.linspace(self.metadata['expstart'].mjd,
                                     expend,
                                     num_intervals,
                                     endpoint=True)

        # Generate the path to the engineering file
        self._engineering_file()
        # Using the telemetry data for the SPT file, compute HST (lon, lat, z)
        if os.path.isfile(self.telemetry_file):
            orbital_params = orbit.HSTOrbit(self.telemetry_file)
            # compute coords at beginning and end of exposure
            for t in time_intervals:
                rect, vel = orbital_params.getPos(t)
                r, ra, dec = rectToSph(rect)
                altitude_list.append(r - R_earth.to('km').value)
                lat = dec
                lon = ra - 2 * np.pi * gmst(t)
                if lon < 0:
                    lon += 2 * np.pi
                lon /= DEGtoRAD
                lat /= DEGtoRAD
                lat_list.append(lat)
                lon_list.append(lon)

            self.metadata['latitude'] = np.asarray(lat_list)
            self.metadata['longitude'] = np.asarray(lon_list)
            self.metadata['altitude'] = np.asarray(altitude_list)
            self.metadata['time_intervals'] = time_intervals
        else:
            LOG.info('SPT file not found, place it in the data directory')
            # If the SPT file for some reason doesn't exist, save NaNs
            self.metadata['altitude'] = np.nan
            self.metadata['latitude'] = np.nan
            self.metadata['longitude'] = np.nan
            self.metadata['time_intervals'] = np.nan