Exemplo n.º 1
0
  def LN_ICRS_to_AltAz(self,ra=None,dec=None,ln_pressure_qfe=None,ln_temperature=None,ln_humidity=None,obstime=None,mount_set_icrs=True):
    ln_pos_eq.ra=ra
    ln_pos_eq.dec=dec
    if mount_set_icrs:
      # libnova corrections for catalog data ...
      # ToDo missing see Jean Meeus, Astronomical Algorithms, chapter 23
      # proper motion
      # annual paralax (0".8)
      # gravitational deflection of light (0".003)
      ln.ln_get_equ_prec(byref(ln_pos_eq), c_double(obstime.jd), byref(ln_pos_eq_pr))
      ln_pos_eq_nut=self.LN_nutation_meeus(eq_pr=ln_pos_eq_pr,JD=obstime.jd)
      ln.ln_get_equ_aber(byref(ln_pos_eq_nut), c_double(obstime.jd), byref(ln_pos_eq_ab))
      ln.ln_get_hrz_from_equ(byref(ln_pos_eq_ab), byref(self.ln_obs), c_double(obstime.jd), byref(ln_pos_aa_ab))
      # here we use QFE not pressure at sea level!
      # E.g. at Dome-C this formula:
      # ln_pressure=ln_see_pres * pow(1. - (0.0065 * ln_alt) / 288.15, (9.80665 * 0.0289644) / (8.31447 * 0.0065));
      # is not precise.
      if self.refraction_method is None:
        d_alt_deg=ln.ln_get_refraction_adj(c_double(ln_pos_aa_ab.alt),c_double(ln_pressure_qfe),c_double(ln_temperature))
      else:
        d_alt_deg=180./np.pi* self.refraction_method(alt=ln_pos_aa_ab.alt,tem=ln_temperature,pre=ln_pressure_qfe,hum=ln_humidity)
    else:
      # ... but not for the star position as measured in mount frame
      ln.ln_get_hrz_from_equ(byref(ln_pos_eq), byref(self.ln_obs), c_double(obstime.jd), byref(ln_pos_aa_ab));
      d_alt_deg=0.
  
    a_az=Longitude(ln_pos_aa_ab.az,u.deg)
    a_az.wrap_at(0.*u.degree)
    a_alt=Latitude(ln_pos_aa_ab.alt + d_alt_deg,u.deg)

    pos_aa=SkyCoord(az=a_az.radian,alt=a_alt.radian,unit=(u.radian,u.radian),frame='altaz',location=self.obs,obstime=obstime,obswl=0.5*u.micron, pressure=ln_pressure_qfe*u.hPa,temperature=ln_temperature*u.deg_C,relative_humidity=ln_humidity)
    return pos_aa
Exemplo n.º 2
0
    def coordinates(self, coord_type='world', origin=0, mode='center'):
        """
        Sky coordinate images.

        Parameters
        ----------
        coord_type : {'world', 'pix', 'skycoord'}
            Which type of coordinates to return.
        origin : {0, 1}
            Pixel coordinate origin.
        mode : {'center', 'edges'}
            Return coordinate values at the pixels edges or pixel centers.
        """
        if mode == 'center':
            y, x = np.indices(self.data.shape)
        elif mode == 'edges':
            shape = self.data.shape[0] + 1, self.data.shape[1] + 1 
            y, x = np.indices(shape)
            y, x = y - 0.5, x - 0.5
        else:
            raise ValueError('Invalid mode to compute coordinates.')
        
        if coord_type == 'pix':
            return x, y
        else:
            xsky, ysky = self.wcs.wcs_pix2world(x, y, origin)
            l, b = Longitude(xsky, unit='deg'), Latitude(ysky, unit='deg')
            l = l.wrap_at('180d')
            if coord_type == 'world':
                return l.degree, b.degree
            elif coord_type == 'skycoord': 
                return l, b
            else:
                raise ValueError("Not a valid coordinate type. Choose either"
                                 " 'world', 'pix' or 'skycoord'.")
Exemplo n.º 3
0
	def calculate(self):
		ephem_location = ephem.Observer()
		ephem_location.lat = self.location.latitude.to(u.rad) / u.rad
		ephem_location.lon = self.location.longitude.to(u.rad) / u.rad
		ephem_location.elevation = self.location.height / u.meter
		ephem_location.date = ephem.Date(self.time.datetime)

		if self.data is None:
			self.alt = Latitude([], unit=u.deg)
			self.az = Longitude([], unit=u.deg)
			self.names = Column([], dtype=np.str)
			self.vmag = Column([])
		else:
			ra = Longitude((self.data['RAh'], self.data['RAm'], self.data['RAs']), u.h)
			dec = Latitude((np.core.defchararray.add(self.data['DE-'], self.data['DEd'].astype(str)).astype(int), self.data['DEm'], self.data['DEs']), u.deg)
			c = SkyCoord(ra, dec, frame='icrs')
			altaz = c.transform_to(AltAz(obstime=self.time, location=self.location))
			self.alt = altaz.alt
			self.az = altaz.az

			self.names = self.data['Name']
			self.vmag = self.data['Vmag']

		for ephemeris in self.ephemerides:
			ephemeris.compute(ephem_location)
			self.vmag = self.vmag.insert(0, ephemeris.mag)
			self.alt = self.alt.insert(0, (ephemeris.alt.znorm * u.rad).to(u.deg))
			self.az = self.az.insert(0, (ephemeris.az * u.rad).to(u.deg))
			self.names = self.names.insert(0, ephemeris.name)
		
		return self.names, self.vmag, self.alt, self.az
def gmst2time(gmst, time):
        """
        Converts a Greenwich Mean Sidereal Time to UTC time, for a given date.

        Parameters
        ----------
        gmst: ~float
            Greenwich Mean Siderial Time (hours)
        time : astropy.time.Time
            UT date+time

        Returns
        -------
        astropy.time.Time object with closest UT day+time at which
            siderial time is correct.
        """
        dgmst = Longitude(gmst - time2gmst(time))
        return time+TimeDelta(dgmst.to(u.hourangle).value*0.9972695663/24.,
                              format='jd')
Exemplo n.º 5
0
    def pixel_to_data(self, x, y, origin=0):
        """
        Convert a pixel coordinate to a data (world) coordinate by using
        `~astropy.wcs.WCS.wcs_pix2world`.

        Parameters
        ----------

        x : float
            Pixel coordinate of the CTYPE1 axis. (Normally solar-x).

        y : float
            Pixel coordinate of the CTYPE2 axis. (Normally solar-y).

        origin : int
            Origin of the top-left corner. i.e. count from 0 or 1.
            Normally, origin should be 0 when passing numpy indices, or 1 if
            passing values from FITS header or map attributes.
            See `~astropy.wcs.WCS.wcs_pix2world` for more information.

        Returns
        -------

        x : `~astropy.units.Quantity`
            Coordinate of the CTYPE1 axis. (Normally solar-x).

        y : `~astropy.units.Quantity`
            Coordinate of the CTYPE2 axis. (Normally solar-y).
        """
        x, y = self.wcs.wcs_pix2world(x, y, origin)

        # If the wcs is celestial it is output in degress
        if self.wcs.is_celestial:
            x *= u.deg
            y *= u.deg
        else:
            x *= self.units.x
            y *= self.units.y

        x = Longitude(x, wrap_angle=180 * u.deg)
        y = Latitude(y)

        return x.to(self.units.x), y.to(self.units.y)
Exemplo n.º 6
0
def diff_rot(duration, latitude, rot_type='howard', frame_time='sidereal'):
    """
    This function computes the change in longitude over days in degrees.

    Parameters
    -----------
    duration : `~astropy.units.Quantity`
        Number of seconds to rotate over.
    latitude : `~astropy.units.Quantity`
        heliographic coordinate latitude in Degrees.
    rot_type : `str`
        The differential rotation model to use.

        One of:

        | ``howard`` : Use values for small magnetic features from Howard et al.
        | ``snodgrass`` : Use Values from Snodgrass et. al
        | ``allen`` : Use values from Allen's Astrophysical Quantities, and simpler equation.

    frame_time : `str`
        One of : ``'sidereal'`` or  ``'synodic'``. Choose 'type of day' time reference frame.

    Returns
    -------
    longitude_delta : `~astropy.units.Quantity`
        The change in longitude over days (units=degrees)

    References
    ----------

    * `IDL code equivalent <http://hesperia.gsfc.nasa.gov/ssw/gen/idl/solar/diff_rot.pro>`__
    * `Howard rotation <http://adsabs.harvard.edu/abs/1990SoPh..130..295H>`__
    * `A review of rotation parameters (including Snodgrass values) <http://link.springer.com/article/10.1023%2FA%3A1005226402796>`__

    Examples
    --------

    Default rotation calculation over two days at 30 degrees latitude:

    >>> import numpy as np
    >>> import astropy.units as u
    >>> from sunpy.physics.differential_rotation import diff_rot
    >>> rotation = diff_rot(2 * u.day, 30 * u.deg)

    Default rotation over two days for a number of latitudes:

    >>> rotation = diff_rot(2 * u.day, np.linspace(-70, 70, 20) * u.deg)

    With rotation type 'allen':

    >>> rotation = diff_rot(2 * u.day, np.linspace(-70, 70, 20) * u.deg, 'allen')
    """

    latitude = latitude.to(u.deg)

    sin2l = (np.sin(latitude))**2
    sin4l = sin2l**2

    rot_params = {
        'howard': [2.894, -0.428, -0.370] * u.urad / u.second,
        'snodgrass': [2.851, -0.343, -0.474] * u.urad / u.second,
        'allen': [14.44, -3.0, 0] * u.deg / u.day
    }

    if rot_type not in ['howard', 'allen', 'snodgrass']:
        raise ValueError(("rot_type must equal one of "
                          "{{ {} }}".format(" | ".join(rot_params.keys()))))

    A, B, C = rot_params[rot_type]

    rotation = (A + B * sin2l + C * sin4l) * duration

    if frame_time == 'synodic':
        rotation -= 0.9856 * u.deg / u.day * duration

    return Longitude(rotation.to(u.deg))
Exemplo n.º 7
0
def test_longitude(tmpdir):
    tree = {'angle': Longitude(-100, u.deg, wrap_angle=180*u.deg)}
    assert_roundtrip_tree(tree, tmpdir)
Exemplo n.º 8
0
def get_altaz(obj_name, ipt_lon, ipt_lat, t=None):

    #for html scrapping
    #from lxml import html
    #from bs4 import BeautifulSoup
    #to place requests
    import requests
    import json

    import astropy.units as u
    from astropy.time import Time
    from astropy.coordinates import SkyCoord, EarthLocation, Angle, Latitude, Longitude

    from astroplan import FixedTarget, Observer
    from astroquery.simbad import Simbad as simbad

    import ephem

    if t == None: t = Time.now()

    ## Set up the observer
    obs_el = 100 * u.m
    loc = EarthLocation.from_geodetic(ipt_lon, ipt_lat, obs_el)
    my_site = Observer(name='My_Site', location=loc)

    obs_lat = my_site.location.lat
    obs_lon = my_site.location.lon

    #observer for pyephem
    ephem_site = ephem.Observer()
    ephem_site.lon, ephem_site.lat = str(obs_lon.deg), str(obs_lat.deg)
    ephem_site.date = ephem.Date(str(t.decimalyear))

    ##Get the object
    #Check for planet-hood.
    #if planet: resolve the individual planet with pyephem.
    #else if satellite or ISS (or TIANGONG) scrap the appropriate websites and return info
    #else query simbad

    ############
    # Put in an auto-correct for kids
    ############
    #just make it lower case for now

    obj_name = obj_name.lower()

    if obj_name in [
            "sun", "mercury", "venus", "moon", "mars", "jupiter", "saturn",
            "uranus", "neptune", "pluto"
    ]:

        if obj_name == "sun": my_planet = ephem.Sun()
        elif obj_name == "mercury": my_planet = ephem.Mercury()
        elif obj_name == "venus": my_planet = ephem.Venus()
        elif obj_name == "moon": my_planet = ephem.Moon()
        elif obj_name == "mars": my_planet = ephem.Mars()
        elif obj_name == "jupiter": my_planet = ephem.Jupiter()
        elif obj_name == "saturn": my_planet = ephem.Saturn()
        elif obj_name == "uranus": my_planet = ephem.Uranus()
        elif obj_name == "neptune": my_planet = ephem.Neptune()
        elif obj_name == "pluto": my_planet = ephem.Pluto()

        my_planet.compute(ephem_site)
        az = my_planet.az * 180 / 3.1415926535
        alt = my_planet.alt * 180 / 3.1415926535
#here coded for just ISS but for all satellites we should have similar setups, probably poll site
    elif (obj_name == "iss"):
        #try a request for the iss from the open notify site. Gives current json data
        page = requests.get("http://api.open-notify.org/iss-now.json")
        issdata = page.json()
        tstamp = issdata['timestamp']
        isslat = issdata['iss_position']['latitude']
        isslon = issdata['iss_position']['longitude']
        #there are issues with just this amount of data as you do not know the altitude of the object
        #here we fix it to 350 km
        issheight = 350 * u.km
        isslat = Latitude(isslat, unit=u.deg)
        isslon = Longitude(isslon, unit=u.deg)

        #there are issues however as this data does NOT contain the altitude so lets try scrapping the html
        #the issue with fullissdata is that it contains information in NASA style units (M50 Cartesian & M50 Keplerian)
        page = requests.get(
            "http://spaceflight.nasa.gov/realdata/sightings/SSapplications/Post/JavaSSOP/orbit/ISS/SVPOST.html"
        )
        #fullissdata=html.fromstring(page.text)

        #there are also other satellites liseted in, issue is parsing the information as I do not know what each field contains
        #the issue here is that all sat data contains unknown units and uncertain which entries contain useful information
        page = requests.get(
            "http://www.celestrak.com/NORAD/elements/stations.txt")
        allsatdata = page.text

        c = SkyCoord(isslon, isslat, issheight)
        my_target = FixedTarget(name='ISS', coord=c)
        az = my_site.altaz(t, my_target).az.deg
        alt = my_site.altaz(t, my_target).alt.deg
    else:
        try:
            q = simbad.query_object(obj_name)
            c = SkyCoord(q["RA"][0], q["DEC"][0], unit=(u.hourangle, u.deg))
            my_star = FixedTarget(name='my_star', coord=c)

            az = my_site.altaz(t, my_star).az.deg
            alt = my_site.altaz(t, my_star).alt.deg
        except:
            print("Couldn't find Object in Database")
            alt, az = 0, 0

    return alt, az
Exemplo n.º 9
0
def nai_detector_radecs(detectors, scx, scz, time):
    """
    calculates the RA/DEC for each NaI detector given spacecraft z and x RA/DEC
    positions.

    NB: This routine is based on code found in GTBURST, originally written by
    Dr Giacamo Vianello for the Fermi Science Tools.

    Parameters
    ----------

    detectors : `dict`
        A dictionary containing the Fermi/GBM detector pointing angles relative
        to the spacecraft axes. Obtained from the nai_detector_angles function.
    scx : array-like
        Two-element tuple containing the RA/DEC information of the Fermi
        spacecraft X-axis
    scz : array-like
        Two-element tuple containing the RA/DEC information of the Fermi
        spacecraft Z-axis
    time : `datetime.datetime`
        The time corresponding to the input scx and scz values, in a format
        understandable by parse_time.

    Returns
    -------
    `dict`
        A dictionary containing the RA/DEC for each Fermi/GBM NaI detector at
        the given input time.
    """

    scx_vector = (np.array([
        np.cos(scx[0].to('rad').value) * np.cos(scx[1].to('rad').value),
        np.sin(scx[0].to('rad').value) * np.cos(scx[1].to('rad').value),
        np.sin(scx[1].to('rad').value)
    ]))

    scz_vector = (np.array([
        np.cos(scz[0].to('rad').value) * np.cos(scz[1].to('rad').value),
        np.sin(scz[0].to('rad').value) * np.cos(scz[1].to('rad').value),
        np.sin(scz[1].to('rad').value)
    ]))

    # For each detector, do the rotation depending on the detector zenith and
    # azimuth angles.
    detector_radecs = copy.deepcopy(detectors)
    for l, d in detectors.items():
        phi = d[0].value
        theta = d[1].value

        # rotate about spacecraft z-axis first
        vx_primed = rotate_vector(scx_vector, scz_vector, np.deg2rad(phi))

        # now find spacecraft y-axis using cross product
        vy_primed = np.cross(scz_vector, vx_primed)

        # do the second part of the rotation around vy
        vz_primed = rotate_vector(scz_vector, vy_primed, np.deg2rad(theta))

        # now we should be pointing at the new RA/DEC.
        ra = Longitude(
            np.degrees(np.arctan2(vz_primed[1], vz_primed[0])) * u.deg)
        dec = Latitude(np.degrees(np.arcsin(vz_primed[2])) * u.deg)

        # save the RA/DEC in a dictionary
        detector_radecs[l] = [ra, dec]

    detector_radecs['time'] = time
    return detector_radecs
Exemplo n.º 10
0
 def from_tree(cls, node, ctx):
     wrap_angle = node['wrap_angle']
     return Longitude(super().from_tree(node, ctx), wrap_angle=wrap_angle)
Exemplo n.º 11
0
def test_representations_api():
    from astropy.coordinates.representation import SphericalRepresentation, \
        UnitSphericalRepresentation, PhysicsSphericalRepresentation, \
        CartesianRepresentation
    from astropy.coordinates import Angle, Longitude, Latitude, Distance

    # <-----------------Classes for representation of coordinate data-------------->
    # These classes inherit from a common base class and internally contain Quantity
    # objects, which are arrays (although they may act as scalars, like numpy's
    # length-0  "arrays")

    # They can be initialized with a variety of ways that make intuitive sense.
    # Distance is optional.
    UnitSphericalRepresentation(lon=8 * u.hour, lat=5 * u.deg)
    UnitSphericalRepresentation(lon=8 * u.hourangle, lat=5 * u.deg)
    SphericalRepresentation(lon=8 * u.hourangle,
                            lat=5 * u.deg,
                            distance=10 * u.kpc)

    # In the initial implementation, the lat/lon/distance arguments to the
    # initializer must be in order. A *possible* future change will be to allow
    # smarter guessing of the order.  E.g. `Latitude` and `Longitude` objects can be
    # given in any order.
    UnitSphericalRepresentation(Longitude(8, u.hour), Latitude(5, u.deg))
    SphericalRepresentation(Longitude(8, u.hour), Latitude(5, u.deg),
                            Distance(10, u.kpc))

    # Arrays of any of the inputs are fine
    UnitSphericalRepresentation(lon=[8, 9] * u.hourangle, lat=[5, 6] * u.deg)

    # Default is to copy arrays, but optionally, it can be a reference
    UnitSphericalRepresentation(lon=[8, 9] * u.hourangle,
                                lat=[5, 6] * u.deg,
                                copy=False)

    # strings are parsed by `Latitude` and `Longitude` constructors, so no need to
    # implement parsing in the Representation classes
    UnitSphericalRepresentation(lon=Angle('2h6m3.3s'), lat=Angle('0.1rad'))

    # Or, you can give `Quantity`s with keywords, and they will be internally
    # converted to Angle/Distance
    c1 = SphericalRepresentation(lon=8 * u.hourangle,
                                 lat=5 * u.deg,
                                 distance=10 * u.kpc)

    # Can also give another representation object with the `reprobj` keyword.
    c2 = SphericalRepresentation.from_representation(c1)

    #  distance, lat, and lon typically will just match in shape
    SphericalRepresentation(lon=[8, 9] * u.hourangle,
                            lat=[5, 6] * u.deg,
                            distance=[10, 11] * u.kpc)
    # if the inputs are not the same, if possible they will be broadcast following
    # numpy's standard broadcasting rules.
    c2 = SphericalRepresentation(lon=[8, 9] * u.hourangle,
                                 lat=[5, 6] * u.deg,
                                 distance=10 * u.kpc)
    assert len(c2.distance) == 2
    # when they can't be broadcast, it is a ValueError (same as Numpy)
    with pytest.raises(ValueError):
        c2 = UnitSphericalRepresentation(lon=[8, 9, 10] * u.hourangle,
                                         lat=[5, 6] * u.deg)

    # It's also possible to pass in scalar quantity lists with mixed units. These
    # are converted to array quantities following the same rule as `Quantity`: all
    # elements are converted to match the first element's units.
    c2 = UnitSphericalRepresentation(
        lon=Angle([8 * u.hourangle, 135 * u.deg]),
        lat=Angle([5 * u.deg, (6 * np.pi / 180) * u.rad]))
    assert c2.lat.unit == u.deg and c2.lon.unit == u.hourangle
    npt.assert_almost_equal(c2.lon[1].value, 9)

    # The Quantity initializer itself can also be used to force the unit even if the
    # first element doesn't have the right unit
    lon = u.Quantity([120 * u.deg, 135 * u.deg], u.hourangle)
    lat = u.Quantity([(5 * np.pi / 180) * u.rad, 0.4 * u.hourangle], u.deg)
    c2 = UnitSphericalRepresentation(lon, lat)

    # regardless of how input, the `lat` and `lon` come out as angle/distance
    assert isinstance(c1.lat, Angle)
    assert isinstance(
        c1.lat,
        Latitude)  # `Latitude` is an `~astropy.coordinates.Angle` subclass
    assert isinstance(c1.distance, Distance)

    # but they are read-only, as representations are immutable once created
    with pytest.raises(AttributeError):
        c1.lat = Latitude(5, u.deg)
    # Note that it is still possible to modify the array in-place, but this is not
    # sanctioned by the API, as this would prevent things like caching.
    c2.lat[:] = [0] * u.deg  # possible, but NOT SUPPORTED

    # To address the fact that there are various other conventions for how spherical
    # coordinates are defined, other conventions can be included as new classes.
    # Later there may be other conventions that we implement - for now just the
    # physics convention, as it is one of the most common cases.
    _ = PhysicsSphericalRepresentation(phi=120 * u.deg,
                                       theta=85 * u.deg,
                                       r=3 * u.kpc)

    # first dimension must be length-3 if a lone `Quantity` is passed in.
    c1 = CartesianRepresentation(np.random.randn(3, 100) * u.kpc)
    assert c1.xyz.shape[0] == 3
    assert c1.xyz.unit == u.kpc
    assert c1.x.shape[0] == 100
    assert c1.y.shape[0] == 100
    assert c1.z.shape[0] == 100
    # can also give each as separate keywords
    CartesianRepresentation(x=np.random.randn(100) * u.kpc,
                            y=np.random.randn(100) * u.kpc,
                            z=np.random.randn(100) * u.kpc)
    # if the units don't match but are all distances, they will automatically be
    # converted to match `x`
    xarr, yarr, zarr = np.random.randn(3, 100)
    c1 = CartesianRepresentation(x=xarr * u.kpc,
                                 y=yarr * u.kpc,
                                 z=zarr * u.kpc)
    c2 = CartesianRepresentation(x=xarr * u.kpc, y=yarr * u.kpc, z=zarr * u.pc)
    assert c1.xyz.unit == c2.xyz.unit == u.kpc
    assert_allclose((c1.z / 1000) - c2.z, 0 * u.kpc, atol=1e-10 * u.kpc)

    # representations convert into other representations via  `represent_as`
    srep = SphericalRepresentation(lon=90 * u.deg,
                                   lat=0 * u.deg,
                                   distance=1 * u.pc)
    crep = srep.represent_as(CartesianRepresentation)
    assert_allclose(crep.x, 0 * u.pc, atol=1e-10 * u.pc)
    assert_allclose(crep.y, 1 * u.pc, atol=1e-10 * u.pc)
    assert_allclose(crep.z, 0 * u.pc, atol=1e-10 * u.pc)
Exemplo n.º 12
0
def _sun_pos(date):
    """
    Calculate solar ephemeris parameters.  Allows for planetary and lunar
    perturbations in the calculation of solar longitude at date and various
    other solar positional parameters. This routine is a truncated version of
    Newcomb's Sun and is designed to give apparent angular coordinates (T.E.D)
    to a precision of one second of time.  This function replicates the SSW/
    IDL function "sun_pos.pro".  This function is assigned to be
    internal at the moment as it should really be replaced by accurate
    ephemeris calculations in the part of SunPy that handles ephemeris.

    Parameters
    -----------
    date : `sunpy.time.time`
        Time at which the solar ephemeris parameters are calculated.  The
        input time can be in any acceptable time format.

    Returns
    -------
    A dictionary with the following keys with the following meanings:

    longitude  -  Longitude of sun for mean equinox of date (degs)
    ra         -  Apparent RA for true equinox of date (degs)
    dec        -  Apparent declination for true equinox of date (degs)
    app_long   -  Apparent longitude (degs)
    obliq      -  True obliquity (degs)

    Notes
    -----
    SSWIDL code equivalent:
        http://hesperia.gsfc.nasa.gov/ssw/gen/idl/solar/sun_pos.pro

    Examples
    --------
    >>> sp = _sun_pos('2013-03-27')
    """
    # Fractional Julian day with correct offset
    dd = julian_day(date) - 2415020.0

    # form time in Julian centuries from 1900.0
    t = dd / 36525.0

    # form sun's mean longitude
    l = (279.6966780 + np.mod(36000.7689250 * t, 360.00)) * 3600.0

    # allow for ellipticity of the orbit (equation of centre) using the Earth's
    # mean anomaly ME
    me = 358.4758440 + np.mod(35999.049750 * t, 360.0)
    ellcor = (6910.10 - 17.20 * t) * np.sin(np.deg2rad(me)) + \
    72.30 * np.sin(np.deg2rad(2.0 * me))
    l = l + ellcor

    # allow for the Venus perturbations using the mean anomaly of Venus MV
    mv = 212.603219 + np.mod(58517.8038750 * t, 360.0)
    vencorr = 4.80 * np.cos(np.deg2rad(299.10170 + mv - me)) + \
          5.50 * np.cos(np.deg2rad(148.31330 + 2.0 * mv - 2.0 * me)) + \
          2.50 * np.cos(np.deg2rad(315.94330 + 2.0 * mv - 3.0 * me)) + \
          1.60 * np.cos(np.deg2rad(345.25330 + 3.0 * mv - 4.0 * me)) + \
          1.00 * np.cos(np.deg2rad(318.150 + 3.0 * mv - 5.0 * me))
    l = l + vencorr

    # Allow for the Mars perturbations using the mean anomaly of Mars MM
    mm = 319.5294250 + np.mod(19139.858500 * t, 360.0)
    marscorr = 2.0 * np.cos(np.deg2rad(343.88830 - 2.0 * mm + 2.0 * me)) + \
            1.80 * np.cos(np.deg2rad(200.40170 - 2.0 * mm + me))
    l = l + marscorr

    # Allow for the Jupiter perturbations using the mean anomaly of Jupiter MJ
    mj = 225.3283280 + np.mod(3034.69202390 * t, 360.00)
    jupcorr = 7.20 * np.cos(np.deg2rad(179.53170 - mj + me)) + \
          2.60 * np.cos(np.deg2rad(263.21670 - mj)) + \
          2.70 * np.cos(np.deg2rad(87.14500 - 2.0 * mj + 2.0 * me)) + \
          1.60 * np.cos(np.deg2rad(109.49330 - 2.0 * mj + me))
    l = l + jupcorr

    # Allow for the Moons perturbations using the mean elongation of the Moon
    # from the Sun D
    d = 350.73768140 + np.mod(445267.114220 * t, 360.0)
    mooncorr = 6.50 * np.sin(np.deg2rad(d))
    l = l + mooncorr

    # Note the original code is
    # longterm  = + 6.4d0 * sin(( 231.19d0  +  20.20d0 * t )*!dtor)
    longterm = 6.40 * np.sin(np.deg2rad(231.190 + 20.20 * t))
    l = l + longterm
    l = np.mod(l + 2592000.0, 1296000.0)
    longmed = l / 3600.0

    # Allow for Aberration
    l = l - 20.5

    # Allow for Nutation using the longitude of the Moons mean node OMEGA
    omega = 259.1832750 - np.mod(1934.1420080 * t, 360.0)
    l = l - 17.20 * np.sin(np.deg2rad(omega))

    # Form the True Obliquity
    oblt = 23.4522940 - 0.01301250 * t + \
    (9.20 * np.cos(np.deg2rad(omega))) / 3600.0

    # Form Right Ascension and Declination
    l = l / 3600.0
    ra = np.rad2deg(np.arctan2(np.sin(np.deg2rad(l)) * \
                        np.cos(np.deg2rad(oblt)), np.cos(np.deg2rad(l))))

    if isinstance(ra, np.ndarray):
        ra[ra < 0.0] += 360.0
    elif ra < 0.0:
        ra = ra + 360.0

    dec = np.rad2deg(np.arcsin(np.sin(np.deg2rad(l)) *
                               np.sin(np.deg2rad(oblt))))

    # convert the internal variables to those listed in the top of the
    # comment section in this code and in the original IDL code.  Quantities
    # are assigned following the advice in Astropy "Working with Angles"
    return {"longitude": Longitude(longmed, u.deg),
            "ra": Longitude(ra, u.deg),
            "dec": Latitude(dec, u.deg),
            "app_long": Longitude(l, u.deg),
            "obliq": Angle(oblt, u.deg)}
Exemplo n.º 13
0
def _L0(time='now',
        light_travel_time_correction=True,
        nearest_point=True,
        aberration_correction=False):
    """
    Return the L0 angle for the Sun at a specified time, which is the apparent Carrington longitude
    of the Sun-disk center as seen from Earth.

    Observer corrections can be disabled, and then this function will instead return the true
    Carrington longitude.

    Parameters
    ----------
    time : {parse_time_types}
        Time to use in a parse_time-compatible format
    light_travel_time_correction : `bool`
        If True, apply the correction for light travel time from Sun to Earth.  Defaults to True.
    nearest_point : `bool`
        If True, calculate the light travel time to the nearest point on the Sun's surface rather
        than the light travel time to the center of the Sun (i.e., a difference of the solar
        radius).  Defaults to True.
    aberration_correction : `bool`
        If True, apply the stellar-aberration correction due to Earth's motion.  Defaults to False.

    Returns
    -------
    `~astropy.coordinates.Longitude`
        The Carrington longitude

    Notes
    -----
    This longitude is calculated using current IAU values (Seidelmann et al. 2007 and later), which
    do not include the effects of light travel time and aberration due to Earth's motion (see that
    paper's Appendix).  This function then, by default, applies the light-travel-time correction
    for the nearest point on the Sun's surface, but does not apply the stellar-aberration correction
    due to Earth's motion.

    We do not apply the stellar-abberation correction by default because it should not be applied
    for purposes such as co-aligning images that are each referenced to Sun-disk center.  Stellar
    aberration does not shift the apparent positions of solar features relative to the Sun-disk
    center.

    The Astronomical Almanac applies the stellar-aberration correction in their printed published
    L0 values (see also Urban & Kaplan 2007).  Applying the stellar-aberration correction due to
    Earth's motion decreases the apparent Carrington longitude by ~20.5 arcseconds.

    References
    ----------
    * Seidelmann et al. (2007), "Report of the IAU/IAG Working Group on cartographic coordinates
      and rotational elements: 2006" `(link) <http://dx.doi.org/10.1007/s10569-007-9072-y>`__
    * Urban & Kaplan (2007), "Investigation of Change in the Computational Technique of the Sun's
      Physical Ephemeris in The Astronomical Almanac"
      `(link) <http://asa.hmnao.com/static/files/sun_rotation_change.pdf>`__
    """
    obstime = parse_time(time)
    earth = get_earth(obstime)

    # Calculate the de-tilt longitude of the Earth
    dlon_earth = _detilt_lon(earth)

    # Calculate the distance to the nearest point on the Sun's surface
    distance = earth.radius - _RSUN if nearest_point else earth.radius

    # Apply a correction for aberration due to Earth motion
    # This expression is an approximation to reduce computations (e.g., it does not account for the
    # inclination of the Sun's rotation axis relative to the ecliptic), but the estimated error is
    # <0.2 arcseconds
    if aberration_correction:
        dlon_earth -= 20.496 * u.arcsec * 1 * u.AU / earth.radius

    # Antedate the observation time to account for light travel time for the Sun-Earth distance
    antetime = (
        obstime -
        distance / speed_of_light) if light_travel_time_correction else obstime

    # Calculate the de-tilt longitude of the meridian due to the Sun's sidereal rotation
    dlon_meridian = Longitude(_DLON_MERIDIAN +
                              (antetime - _J2000) * 14.1844 * u.deg / u.day)

    return Longitude(dlon_earth - dlon_meridian)
Exemplo n.º 14
0
import cdshealpix

from cdshealpix import elliptical_cone_search
import astropy.units as u
from astropy.coordinates import Angle, SkyCoord, Longitude, Latitude
import numpy as np

ipix, depth, fully_covered = elliptical_cone_search(lon=Longitude(0, u.deg),
                                                    lat=Latitude(0, u.deg),
                                                    a=Angle(50, unit="deg"),
                                                    b=Angle(5, unit="deg"),
                                                    pa=Angle(30, unit="deg"),
                                                    depth=10)

from mocpy import MOC, World2ScreenMPL

moc = MOC.from_healpix_cells(ipix, depth, fully_covered)
# Plot the MOC using matplotlib
import matplotlib.pyplot as plt
fig = plt.figure(111, figsize=(10, 10))
# Define a astropy WCS easily
with World2ScreenMPL(fig,
                     fov=100 * u.deg,
                     center=SkyCoord(0, 0, unit="deg", frame="icrs"),
                     coordsys="icrs",
                     rotation=Angle(0, u.degree),
                     projection="AIT") as wcs:
    ax = fig.add_subplot(1, 1, 1, projection=wcs)
    # Call fill with a matplotlib axe and the `~astropy.wcs.WCS` wcs object.
    moc.fill(ax=ax, wcs=wcs, alpha=0.5, fill=True, color="green")
    # Draw the perimeter of the MOC in black
Exemplo n.º 15
0
    def __init__(self, telemetry_file=None, save_file=None):
        if telemetry_file is not None:
            self.filename = telemetry_file

            self.systime = []
            self.latitude = []
            self.longitude = []
            self.altitude = []

            self.utc_time = []

            pressure_low = []
            pressure_mid = []
            pressure_high = []

            count = 0

            print("Parsing {0}".format(telemetry_file))
            with open(telemetry_file, 'rb') as f:
                pg = parser_generator(f,
                                      filter_systemid=0x05,
                                      filter_tmtype=0x02,
                                      verbose=True)
                for p in pg:
                    count += 1
                    self.systime.append(p['systime'])
                    self.latitude.append(p['user_latitude'])
                    self.longitude.append(p['user_longitude'])
                    self.altitude.append(p['user_altitude'])

                    # Convert time to UTC
                    self.utc_time.append(np.datetime64('1980-01-06T00:00:00Z') +\
                                         np.timedelta64(p['user_week'], 'W') +\
                                         np.timedelta64(int((p['user_timeofweek'] - p['user_offset']) * 1e6), 'us'))

                    pressure_low.append(
                        (p['sip1_pressure_low'] + p['sip2_pressure_low']) / 2)
                    pressure_mid.append(
                        (p['sip1_pressure_mid'] + p['sip2_pressure_mid']) / 2)
                    pressure_high.append(
                        (p['sip1_pressure_high'] + p['sip2_pressure_high']) /
                        2)

            if count > 0:
                self.systime = np.hstack(self.systime)
                self.latitude = Latitude(self.latitude, 'deg')
                self.longitude = Longitude(self.longitude,
                                           'deg',
                                           wrap_angle=180 * u.deg)
                self.altitude = u.Quantity(self.altitude, 'm').to('km')

                self.utc_time = np.hstack(self.utc_time)

                pressure_low = np.hstack(pressure_low)
                pressure_mid = np.hstack(pressure_mid)
                pressure_high = np.hstack(pressure_high)

                # Convert pressure to millibars
                self.pressure = pressure_low * 0.327 - 10.76
                use_mid = pressure_mid < 3165
                self.pressure[use_mid] = pressure_mid[use_mid] * 0.032 - 1.29
                use_high = pressure_high < 3383
                self.pressure[
                    use_high] = pressure_high[use_high] * 0.003 - 0.149

                self.pressure = u.Quantity(self.pressure, 'mbar')

                print("Total packets: {0}".format(count))
            else:
                print("No packets found")

        elif save_file is not None:
            print("Restoring {0}".format(save_file))
            with gzip.open(save_file, 'rb') as f:
                try:
                    saved = pickle.load(f, encoding='latin1')
                except TypeError:
                    saved = pickle.load(f)
                self.filename = saved['filename']
                self.systime = saved['systime']
                self.latitude = saved['latitude']
                self.longitude = saved['longitude']
                self.altitude = saved['altitude']
                self.utc_time = saved['utc_time']
                self.pressure = saved['pressure']
        else:
            raise RuntimeError(
                "Either a telemetry file or a save file must be specified")
Exemplo n.º 16
0
def do_target_observation(i, obstime_utc, telescope_position, csvfile,
                          total_wait):  #, closest_field):
    # Get objects that are close to current observing horizon:
    current_lst = Time(obstime_utc).sidereal_time('apparent', westerbork().lon)

    proposed_ra = (current_lst + Longitude('6h')).wrap_at(360 * u.deg)
    test_slew_seconds = calc_slewtime(
        [telescope_position.ra.radian, telescope_position.dec.radian],
        [proposed_ra.radian, telescope_position.dec.radian])

    avail_fields = apertif_fields[apertif_fields['weights'] > 0]
    availability = SkyCoord(
        np.array(avail_fields['hmsdms']
                 )).ra.hour - proposed_ra.hour - test_slew_seconds / 3600.
    availability[availability < -12.] += 24.

    sun_position = get_sun(Time(obstime_utc, scale='utc'))
    sun_okay = np.array(
        sun_position.separation(SkyCoord(avail_fields['hmsdms'])).value)

    targ_wait = 0.  # minutes
    ##### EDITABLE: Will control the maximum wait time for a target before it gives up and looks for a calibrator #####
    # wait_limit = 5.0  # hours
    wait_limit = 10.0  # hours

    new_obstime_utc = obstime_utc
    # First check what is *already* up.  If nothing, then wait for something to rise.
    ##### If target is passing it's HA limit, adjust availability numbers (especially the second one) #####
    while not np.any((availability < -0.02) & (availability > -0.40)
                     & (sun_okay > args.sun_distance)):
        targ_wait += dowait
        new_obstime_utc = wait_for_rise(new_obstime_utc, waittime=dowait)
        new_lst = Time(new_obstime_utc).sidereal_time('apparent',
                                                      westerbork().lon)
        proposed_ra = (new_lst + Longitude('6h')).wrap_at(360 * u.deg)
        availability = SkyCoord(np.array(
            avail_fields['hmsdms'])).ra.hour - proposed_ra.hour
        availability[availability < -12.] += 24.
        # print(availability, sun_okay > args.sun_distance, sun_okay)
    if (targ_wait != 0.) and (targ_wait <= wait_limit * 60.):
        total_wait += targ_wait
        print(
            "\tTarget not up (or sun issues), waiting {} minutes until LST: {}"
            .format(targ_wait, str(new_lst)))

    if targ_wait <= wait_limit * 60.:
        # Choose M101 field first if available or within a 1 hour wait AND (before this function) if users had requested it in args.repeat_m101
        if 'M1403+5324' in avail_fields[(availability < -0.02)
                                        & (availability > -0.40)]['name']:
            first_field = avail_fields[avail_fields['name'] == 'M1403+5324'][0]
            print(
                "*** M1403+5324 OBSERVED!  WAIT A MONTH TO SCHEDULE AGAIN! ***"
            )
        elif 'M1403+5324' in avail_fields[(availability < 1.00)
                                          & (availability > -0.02)]['name']:
            m101_field = avail_fields[avail_fields['name'] == 'M1403+5324'][0]
            m101_availability = SkyCoord(
                m101_field['hmsdms']).ra.hour - proposed_ra.hour
            while not (m101_availability < -0.02) & (m101_availability >
                                                     -0.40):
                targ_wait += dowait
                new_obstime_utc = wait_for_rise(new_obstime_utc,
                                                waittime=dowait)
                new_lst = Time(new_obstime_utc).sidereal_time(
                    'apparent',
                    westerbork().lon)
                proposed_ra = (new_lst + Longitude('6h')).wrap_at(360 * u.deg)
                m101_availability = SkyCoord(
                    m101_field['hmsdms']).ra.hour - proposed_ra.hour
                # m101_availability[m101_availability < -12] += 24
            first_field = m101_field
            print(
                "*** M1403+5324 OBSERVED!  WAIT A MONTH TO SCHEDULE AGAIN! ***"
            )
        else:
            first_field = avail_fields[(availability < -0.02)
                                       & (availability > -0.40) &
                                       (sun_okay > args.sun_distance)][0]
            check_sun = sun_position.separation(SkyCoord(
                first_field['hmsdms']))
            if check_sun.value < 50.:
                print("\tField is THIS close to Sun: {}".format(check_sun))

        # NOTE SLEW TIME IS CALCULATED TO THE *OBSERVING* HORIZON, NOT TO THE NEW RA!
        # TELESCOPE SHOULD MOVE TO HORIZON AND WAIT!!!
        slew_seconds = calc_slewtime(
            [telescope_position.ra.radian, telescope_position.dec.radian], [
                SkyCoord(first_field['hmsdms']).ra.radian,
                SkyCoord(first_field['hmsdms']).dec.radian
            ])
        if slew_seconds < targ_wait * 60.:
            new_obstime_utc = obstime_utc + datetime.timedelta(
                minutes=targ_wait)
        else:
            new_obstime_utc = obstime_utc + datetime.timedelta(
                seconds=slew_seconds)
        after_target = observe_target(apertif_fields,
                                      new_obstime_utc,
                                      first_field['name'],
                                      obstime=11.5)
        write_to_csv(csvfile, first_field['name'],
                     SkyCoord(first_field['hmsdms']), new_obstime_utc,
                     after_target)
        print("Scan {} observed {}.".format(i, first_field['hmsdms']))
        return i, after_target, SkyCoord(first_field['hmsdms']), total_wait
    else:
        print("\tNo target for {} hours. Go to a calibrator instead.".format(
            targ_wait / 60.))
        i -= 1
        return i, obstime_utc, telescope_position, total_wait
Exemplo n.º 17
0
    def __init__(self,
                 pix_values,
                 lon0,
                 lon1,
                 lat0,
                 lat1,
                 dist0=None,
                 dist1=None,
                 axis_order=('lon', 'lat', 'dist'),
                 frame='galactic',
                 dist_interp='linear'):
        """
        Args:
            pix_values (:obj:`np.ndarray`): An array containing the pixel
                values. For a 3D dust map (with distance), the array should be
                3D, with the order of the axes corresponding to
                :obj:`axis_order`. For a 2D dust map, the array should be 2D.
            lon0 (float): The lower limiting longitude of the map, in deg.
            lon1 (float): The upper limiting longitude of the map, in deg.
            lat0 (float): The lower limiting latitude of the map, in deg.
            lat1 (float): The upper limiting latitude of the map, in deg.
            dist0 (Optional[:obj:`astropy.units.Quantity`]): The lower
                limiting distance of the map. If :obj:`dist0` has units of
                distance of the map. If :obj:`dist0` has units of
                :obj:`'mag'`, then it is assumed to be a distance modulus,
                and the distance bins are assumed to be spaced linearly
                in distance modulus, instead of distance.
            dist1 (Optional[:obj:`astropy.units.Quantity`]): The upper
                limiting distance of the map. If :obj:`dist1` has units of
                :obj:`'mag'`, then it is assumed to be a distance modulus,
                and the distance bins are assumed to be spaced linearly
                in distance modulus, instead of distance.
            axis_order (tuple of str): The order of the axes in 
                :obj:`pix_values`. Defaults to :obj:`('lon','lat','dist')`.
                For 2D maps, do not include :obj:`'dist'`.
            frame (Optional[:obj:`str`]): The coordinate frame to which the
                longitudes and latitudes correspond. Must be a frame
                understood by :obj:`astropy.coordinates.SkyCoord`.
                Defaults to :obj:`'galactic'`.
            dist_interp (:obj:`str`): How to interpolate between distance
                slices in the map. Valid choices are :obj:`'step'` and
                :obj:`'linear'`. Defaults to :obj:`'linear'`.
        """
        self._frame = frame

        # Read (lon, lat, dist) bounds
        self._wrap_angle = lon0 * units.deg
        self._lon_lim = (
            Longitude(lon0, unit='deg', wrap_angle=self._wrap_angle),
            Longitude(lon1, unit='deg', wrap_angle=self._wrap_angle),
        )

        self._lat_lim = (lat0, lat1)

        if dist0 is not None:
            if dist0.unit == 'mag':
                self._dm = True
                self._dist_lim = (dist0.value, dist1.value)
            else:
                self._dm = False
                self._dist_lim = (dist0.to('kpc').value, dist1.to('kpc').value)

        # Read mapping from axis -> (lon, lat, dist)
        self._axis_dist = None

        if len(axis_order) < 2:
            raise ValueError("axis_order must have at least " +
                             "two entries ('lon' and 'lat').")

        for a in ('lon', 'lat'):
            if a not in axis_order:
                raise ValueError("'{}' must be in axis_order.".format(a))

        for i, a in enumerate(axis_order):
            if a == 'lon':
                self._axis_lon = i
            elif a == 'lat':
                self._axis_lat = i
            elif a == 'dist':
                self._axis_dist = i
            else:
                raise ValueError("Unknown entry in axis_order: " +
                                 "'{}'".format(a))

        # Get (lon,lat,dist) grid properties
        self._n_lon = pix_values.shape[self._axis_lon]
        self._n_lat = pix_values.shape[self._axis_lat]

        if self._lon_lim[1] == self._lon_lim[0]:
            self._dlon = 360. / self._n_lon
        else:
            self._dlon = (self._lon_lim[1] - self._lon_lim[0]) / self._n_lon
            self._dlon = self._dlon.to('deg').value
        self._dlat = (self._lat_lim[1] - self._lat_lim[0]) / self._n_lat

        if self._axis_dist is not None:
            self._n_dist = pix_values.shape[self._axis_dist]
            self._ddist = (self._dist_lim[1] -
                           self._dist_lim[0]) / self._n_dist

            if self._dm:
                # Physical distance of each slice (in kpc)
                self._ddist_phys = 10.**(0.2 * np.linspace(
                    self._dist_lim[0], self._dist_lim[1], self._n_dist) - 2.)

        # Get pixel values
        self._pix_values = pix_values
        self._n_axes = len(pix_values.shape)

        self._dist_interp = dist_interp
Exemplo n.º 18
0
    def _coords2idx(self, coords, diff=False):
        c = coords.transform_to(self._frame).represent_as('spherical')

        idx = np.empty(coords.shape + (self._n_axes, ), dtype='i4')

        lon = Longitude(c.lon, wrap_angle=self._wrap_angle)
        lon_idx = (lon - self._lon_lim[0]).to('deg').value / self._dlon
        lat_idx = (c.lat.deg - self._lat_lim[0]) / self._dlat

        lon_idx = np.floor(lon_idx).astype('i4')
        lat_idx = np.floor(lat_idx).astype('i4')

        mask = ((lon_idx < 0) | (lon_idx >= self._n_lon) | (lat_idx < 0) |
                (lat_idx >= self._n_lat))

        if self._axis_dist is not None:
            dist = c.distance.to('kpc').value

            if self._dm:
                dist = 5. * (np.log10(dist) + 2.)

            dist_idx = (dist - self._dist_lim[0]) / self._ddist
            dist_idx_close = np.floor(dist_idx).astype('i4')

            # Differential extinction
            if diff:
                dist_idx_far = (dist_idx_close + 1).clip(0, self._n_dist - 1)
                close_mask = (dist_idx_close < 0)
                far_mask = (dist_idx_close >= self._n_dist)
            elif self._dist_interp == 'step':
                dist_idx_close = dist_idx_close.clip(-1, self._n_dist - 1)
                close_mask = (dist_idx_close == -1)
            elif self._dist_interp == 'linear':
                far_weight = dist_idx - dist_idx_close

                # Beyond farthest distance slice
                far_mask = (dist_idx_close >= self._n_dist - 1)
                if np.any(far_mask):
                    dist_idx_close[far_mask] = self._n_dist - 2
                    far_weight[far_mask] = 1.0

                # Closer than closest distance slice
                close_mask = (dist_idx_close < 0)
                dist_idx_close[close_mask] = -1
                if np.any(close_mask):
                    if self._dm:
                        far_weight[close_mask] = (10.**(
                            0.2 * (dist[close_mask] - self._dist_lim[0])))
                    else:
                        far_weight[close_mask] = (dist[close_mask] /
                                                  self._dist_lim[0])

            #mask |= (dist_idx < 0) | (dist_idx >= self._n_dist)

        if np.any(mask):
            lon_idx[mask] = -1
            lat_idx[mask] = -1

            if self._axis_dist is not None:
                dist_idx_close[mask] = -1

        idx[:, self._axis_lon] = lon_idx
        idx[:, self._axis_lat] = lat_idx

        # Include distance indices
        if self._axis_dist is not None:
            if diff:
                # For differential reddening, need:
                #   1. Index of distance bin just beyond d
                #   2. Mask of out-of-bounds (lon, lat)
                #   3. Mask of which pixels are closer than closest slice
                #   3. Mask of which pixels are farther than farthest slice
                idx[:, self._axis_dist] = dist_idx_far
                return idx, mask, (close_mask, far_mask)
            else:
                idx[:, self._axis_dist] = dist_idx_close

            if self._dist_interp == 'step':
                # For step-function interpolation, need:
                #   1. Index of distance bin just inside d
                #   2. Mask of out-of-bounds (lon, lat)
                #   3. Mask of which pixels are closer than closest slice
                return idx, mask, close_mask
            elif self._dist_interp == 'linear':
                # For piecewise-linear interpolation, need:
                #   1. Index of distance bin just inside d
                #   2. Mask of out-of-bounds (lon, lat)
                #   3. For each pixel, weight to apply to next distance bin
                return idx, mask, far_weight

        return idx, mask, None
Exemplo n.º 19
0
class SkyCatalog:
	def __init__(self, sun_only = False, moon_only = False):
		if sun_only:
			self.ephemerides = [ephem.Sun()]
			self.data = None
		elif moon_only:
			self.ephemerides = [ephem.Moon()]
			self.data = None
		else:
			self.ephemerides = [ephem.Venus(), ephem.Mars(), ephem.Jupiter(), ephem.Saturn(), ephem.Moon(), ephem.Sun()]
			
			self.data = ascii.read(Configuration.star_catalog_file, guess=False, format='fixed_width_no_header', names=('HR', 'Name', 'DM', 'HD', 'SAO', 'FK5', 'IRflag', 'r_IRflag', 'Multiple', 'ADS', 'ADScomp', 'VarID', 'RAh1900', 'RAm1900', 'RAs1900', 'DE-1900', 'DEd1900', 'DEm1900', 'DEs1900', 'RAh', 'RAm', 'RAs', 'DE-', 'DEd', 'DEm', 'DEs', 'GLON', 'GLAT', 'Vmag', 'n_Vmag', 'u_Vmag', 'B-V', 'u_B-V', 'U-B', 'u_U-B', 'R-I', 'n_R-I', 'SpType', 'n_SpType', 'pmRA', 'pmDE', 'n_Parallax', 'Parallax', 'RadVel', 'n_RadVel', 'l_RotVel', 'RotVel', 'u_RotVel', 'Dmag', 'Sep', 'MultID', 'MultCnt', 'NoteFlag'), col_starts=(0, 4, 14, 25, 31, 37, 41, 42, 43, 44, 49, 51, 60, 62, 64, 68, 69, 71, 73, 75, 77, 79, 83, 84, 86, 88, 90, 96, 102, 107, 108, 109, 114, 115, 120, 121, 126, 127, 147, 148, 154, 160, 161, 166, 170, 174, 176, 179, 180, 184, 190, 194, 196), col_ends=(3, 13, 24, 30, 36, 40, 41, 42, 43, 48, 50, 59, 61, 63, 67, 68, 70, 72, 74, 76, 78, 82, 83, 85, 87, 89, 95, 101, 106, 107, 108, 113, 114, 119, 120, 125, 126, 146, 147, 153, 159, 160, 165, 169, 173, 175, 178, 179, 183, 189, 193, 195, 196))
			
			# removed masked rows
			
			self.data = self.data[:][~np.ma.getmaskarray(self.data['DE-'])]
		
	def setLocation(self, location):
		self.location = location
		
	def setTime(self, time):
		self.time = time
		
	def calculate(self):
		ephem_location = ephem.Observer()
		ephem_location.lat = self.location.latitude.to(u.rad) / u.rad
		ephem_location.lon = self.location.longitude.to(u.rad) / u.rad
		ephem_location.elevation = self.location.height / u.meter
		ephem_location.date = ephem.Date(self.time.datetime)

		if self.data is None:
			self.alt = Latitude([], unit=u.deg)
			self.az = Longitude([], unit=u.deg)
			self.names = Column([], dtype=np.str)
			self.vmag = Column([])
		else:
			ra = Longitude((self.data['RAh'], self.data['RAm'], self.data['RAs']), u.h)
			dec = Latitude((np.core.defchararray.add(self.data['DE-'], self.data['DEd'].astype(str)).astype(int), self.data['DEm'], self.data['DEs']), u.deg)
			c = SkyCoord(ra, dec, frame='icrs')
			altaz = c.transform_to(AltAz(obstime=self.time, location=self.location))
			self.alt = altaz.alt
			self.az = altaz.az

			self.names = self.data['Name']
			self.vmag = self.data['Vmag']

		for ephemeris in self.ephemerides:
			ephemeris.compute(ephem_location)
			self.vmag = self.vmag.insert(0, ephemeris.mag)
			self.alt = self.alt.insert(0, (ephemeris.alt.znorm * u.rad).to(u.deg))
			self.az = self.az.insert(0, (ephemeris.az * u.rad).to(u.deg))
			self.names = self.names.insert(0, ephemeris.name)
		
		return self.names, self.vmag, self.alt, self.az

	def filter(self, min_alt, max_mag):
		show = self.alt >= min_alt

		names = self.names[show]
		vmag = self.vmag[show]
		alt = self.alt[show]
		az = self.az[show]

		show_mags = vmag < max_mag

		names = names[show_mags]
		vmag = vmag[show_mags]
		alt = alt[show_mags]
		az = az[show_mags]
		
		return names, vmag, alt, az
Exemplo n.º 20
0
    coord_detilt = coord.hcrs.cartesian.transform(_SUN_DETILT_MATRIX)
    return coord_detilt.represent_as(SphericalRepresentation).lon.to('deg')


# J2000.0 epoch
_J2000 = Time('J2000.0', scale='tt')

# One of the two nodes of intersection between the ICRF equator and Sun's equator in HCRS
_NODE = SkyCoord(_SOLAR_NORTH_POLE_HCRS.lon + 90 * u.deg,
                 0 * u.deg,
                 frame='hcrs')

# The longitude in the de-tilted frame of the Sun's prime meridian.
# The IAU (Seidelmann et al. 2007 and later) defines the true longitude of the meridian (i.e.,
# without light travel time to Earth and aberration effects) as 84.176 degrees eastward at J2000.
_DLON_MERIDIAN = Longitude(_detilt_lon(_NODE) + 84.176 * u.deg)


@add_common_docstring(**_variables_for_parse_time_docstring())
def _L0(time='now',
        light_travel_time_correction=True,
        nearest_point=True,
        aberration_correction=False):
    """
    Return the L0 angle for the Sun at a specified time, which is the apparent Carrington longitude
    of the Sun-disk center as seen from Earth.

    Observer corrections can be disabled, and then this function will instead return the true
    Carrington longitude.

    Parameters
Exemplo n.º 21
0
def nai_detector_radecs(detectors, scx, scz, time):
    """
    calculates the "RA/DEC" for each NaI detector given spacecraft "z" and "x"
    "RA/DEC" positions.

    This routine is based on code found in `GTBURST <https://fermi.gsfc.nasa.gov/ssc/data/analysis/scitools/gtburst.html>`__, originally written by
    Dr Giacamo Vianello for the Fermi Science Tools.

    Parameters
    ----------
    detectors : `dict`
        A dictionary containing the Fermi/GBM detector pointing angles relative
        to the spacecraft axes. Obtained from the
        `sunpy.instr.fermi.nai_detector_angles` function.
    scx : array-like
        Two-element tuple containing the "RA/DEC" information of the Fermi
        spacecraft X-axis
    scz : array-like
        Two-element tuple containing the "RA/DEC" information of the Fermi
        spacecraft Z-axis
    time : {parse_time_types}
        A time specified as a parse_time-compatible
        time string, number, or a datetime object.
        This will correspond to the input ``scx`` and ``scz`` values.

    Returns
    -------
    `dict`
        A dictionary containing the "RA/DEC" for each Fermi/GBM NaI detector at
        the given input time.
    """

    scx_vector = (np.array(
        [np.cos(scx[0].to('rad').value) * np.cos(scx[1].to('rad').value),
         np.sin(scx[0].to('rad').value) * np.cos(scx[1].to('rad').value),
         np.sin(scx[1].to('rad').value)]))

    scz_vector = (np.array(
        [np.cos(scz[0].to('rad').value) * np.cos(scz[1].to('rad').value),
         np.sin(scz[0].to('rad').value) * np.cos(scz[1].to('rad').value),
         np.sin(scz[1].to('rad').value)]))

    # For each detector, do the rotation depending on the detector zenith and
    # azimuth angles.
    detector_radecs = copy.deepcopy(detectors)
    for l, d in detectors.items():
        phi = d[0].value
        theta = d[1].value

        # rotate about spacecraft z-axis first
        vx_primed = rotate_vector(scx_vector, scz_vector, np.deg2rad(phi))

        # now find spacecraft y-axis using cross product
        vy_primed = np.cross(scz_vector, vx_primed)

        # do the second part of the rotation around vy
        vz_primed = rotate_vector(scz_vector, vy_primed, np.deg2rad(theta))

        # now we should be pointing at the new RA/DEC.
        ra = Longitude(
            np.degrees(np.arctan2(vz_primed[1], vz_primed[0])) * u.deg)
        dec = Latitude(np.degrees(np.arcsin(vz_primed[2])) * u.deg)

        # save the RA/DEC in a dictionary
        detector_radecs[l] = [ra, dec]

    detector_radecs['time'] = time
    return detector_radecs
Exemplo n.º 22
0
def diff_rot(duration: u.s, latitude: u.deg, rot_type='howard', frame_time='sidereal'):
    r"""
    This function computes the change in longitude over days in degrees.

    Parameters
    -----------
    duration : `~astropy.units.Quantity`
        Number of seconds to rotate over.
    latitude : `~astropy.units.Quantity`
        heliographic coordinate latitude in Degrees.
    rot_type : `str`
        The differential rotation model to use.

        One of:

        | ``howard`` : Use values from Howard et al. (1990)
        | ``snodgrass`` : Use values from Snodgrass et. al. (1983)
        | ``allen`` : Use values from Allen's Astrophysical Quantities, and simpler equation.

    frame_time : `str`
        One of : ``'sidereal'`` or  ``'synodic'``. Choose 'type of day' time reference frame.

    Returns
    -------
    longitude_delta : `~astropy.units.Quantity`
        The change in longitude over days (units=degrees)

    Notes
    -----
    The rotation rate at a heliographic latitude :math:`\theta` is given by

    .. math::

        A + B \sin^{2} \left (\theta \right ) + C \sin^{4} \left ( \theta \right )

    where :math:`A, B, C` are constants that depend on the model:

    ========= ===== ====== ====== ==========
    Model     A     B      C      Unit
    ========= ===== ====== ====== ==========
    howard    2.894 -0.428 -0.370 microrad/s
    snodgrass 2.851 -0.343 -0.474 microrad/s
    allen     14.44 -3.0   0      deg/day
    ========= ===== ====== ====== ==========

    1 microrad/s is approximately 4.95 deg/day.

    References
    ----------

    * `Solar surface velocity fields determined from small magnetic features (Howard et al. 1990) <https://doi.org/10.1007/BF00156795>`__
    * `A comparison of differential rotation measurements (Beck 2000, includes Snodgrass values) <https://doi.org/10.1023/A:1005226402796>`__

    Examples
    --------

    Default rotation calculation over two days at 30 degrees latitude:

    >>> import numpy as np
    >>> import astropy.units as u
    >>> from sunpy.physics.differential_rotation import diff_rot
    >>> diff_rot(2 * u.day, 30 * u.deg)
    <Longitude 27.36432679 deg>

    Default rotation over two days for a number of latitudes:

    >>> diff_rot(2 * u.day, np.linspace(-70, 70, 20) * u.deg)
    <Longitude [22.05449682, 23.03214991, 24.12033958, 25.210281  ,
                26.21032832, 27.05716463, 27.71932645, 28.19299667,
                28.49196765, 28.63509765, 28.63509765, 28.49196765,
                28.19299667, 27.71932645, 27.05716463, 26.21032832,
                25.210281  , 24.12033958, 23.03214991, 22.05449682] deg>

    With rotation type 'allen':

    >>> diff_rot(2 * u.day, np.linspace(-70, 70, 20) * u.deg, 'allen')
    <Longitude [23.58186667, 24.14800185, 24.82808733, 25.57737945,
            26.34658134, 27.08508627, 27.74430709, 28.28087284,
            28.6594822 , 28.85522599, 28.85522599, 28.6594822 ,
            28.28087284, 27.74430709, 27.08508627, 26.34658134,
            25.57737945, 24.82808733, 24.14800185, 23.58186667] deg>
    """

    latitude = latitude.to(u.deg)

    sin2l = (np.sin(latitude))**2
    sin4l = sin2l**2

    rot_params = {'howard': [2.894, -0.428, -0.370] * u.urad / u.second,
                  'snodgrass': [2.851, -0.343, -0.474] * u.urad / u.second,
                  'allen': [14.44, -3.0, 0] * u.deg / u.day
                  }

    if rot_type not in ['howard', 'allen', 'snodgrass']:
        raise ValueError("rot_type must equal one of "
                         "{{ {} }}".format(" | ".join(rot_params.keys())))

    A, B, C = rot_params[rot_type]

    # This calculation of the rotation assumes a sidereal frame time.
    rotation = (A + B * sin2l + C * sin4l) * duration

    # Applying this correction assumes that the observer is on the Earth,
    # and that the Earth is at the same distance from the Sun at all times
    # during the year.
    if frame_time == 'synodic':
        rotation -= 0.9856 * u.deg / u.day * duration

    return Longitude(rotation.to(u.deg))
Exemplo n.º 23
0
import datetime
import math
from astropy.coordinates import Longitude

from skymap.geometry import SkyCoordDeg, ensure_angle_range
from skymap.coordinates import PrecessionCalculator, REFERENCE_EPOCH

GALACTIC_NORTH_POLE = SkyCoordDeg(Longitude("12h49m").degree, 27.4)
GALACTIC_LONGITUDE_NORTH_CELESTIAL_POLE = 123
GALACTIC_NORTH_POLE_EPOCH = datetime.datetime(1950, 1, 1).date()


# Ecliptic coordinate system
def obliquity_of_the_ecliptic(epoch=REFERENCE_EPOCH):
    """Returns the obliquity of the ecliptic for the given epoch, in degrees.

    The calculation is taken from the Astronomical Almanac 2010, as given
    on https://en.wikipedia.org/wiki/Axial_tilt#Short_term.
    """
    a = 23.0 + 26 / 60.0 + 21.406 / 3600.0
    b = -46.836769 / 3600.0
    c = -0.0001831 / 3600.0
    d = 0.00200340 / 3600.0
    e = -0.576e-6 / 3600.0
    f = -0.0434e-6 / 3600.0
    t = (epoch - REFERENCE_EPOCH).days / 36525.0
    return a + b * t + c * t**2 + d * t**3 + e * t**4 + f * t**5


def ecliptic_to_equatorial(p, epoch=REFERENCE_EPOCH):
    """Returns the equatorial coordinates for the given point in ecliptic coordinates.
Exemplo n.º 24
0
def main():
    """See module docstring"""
    def gamepad_callback(_tracker: Tracker) -> bool:
        """Callback for gamepad control.

        Allows manual control of the slew rate via a gamepad when the 'B' button is held down,
        overriding tracking behavior. This callback is registered with the Tracker object which
        calls it on each control cycle.

        Defined inside main() so this has easy access to objects that are within that scope.

        Args:
            _tracker: A reference to an object of type Tracker. Not used internally.

        Returns:
            True when the 'B' button is depressed which disables the normal control path. False
                otherwise, which leaves the normal control path enabled.
        """
        if game_pad.state.get('BTN_EAST', 0) == 1:
            gamepad_x, gamepad_y = game_pad.get_proportional()
            slew_rates = (mount.max_slew_rate * gamepad_x,
                          mount.max_slew_rate * gamepad_y)
            for idx, axis_name in enumerate(mount.AxisName):
                mount.slew(axis_name, slew_rates[idx])
            return True
        else:
            return False

    parser = track.ArgParser()
    targets.add_program_arguments(parser)
    laser.add_program_arguments(parser)
    mounts.add_program_arguments(parser, meridian_side_required=True)
    ntp.add_program_arguments(parser)
    telem.add_program_arguments(parser)
    control.add_program_arguments(parser)
    args = parser.parse_args()

    # Set priority of this thread to realtime. Do this before constructing objects since priority
    # is inherited and some critical threads are created by libraries we have no direct control
    # over.
    os.sched_setscheduler(0, os.SCHED_RR, os.sched_param(11))

    # Check if system clock is synchronized to GPS
    if args.check_time_sync:
        try:
            ntp.check_ntp_status()
        except ntp.NTPCheckFailure as e:
            print('NTP check failed: ' + str(e))
            if not click.confirm('Continue anyway?', default=True):
                print('Aborting')
                sys.exit(2)

    # Load a MountModel object
    try:
        mount_model = track.model.load_stored_model()
    except track.model.StaleParametersException:
        if click.confirm('Stored alignment parameters are stale. Use anyway?',
                         default=True):
            mount_model = track.model.load_stored_model(max_age=None)
        elif args.target_type == 'camera':
            if click.confirm(
                    'Use a default set of alignment parameters instead?',
                    default=True):
                guide_cam_orientation = click.prompt(
                    'Enter guide camera orientation in degrees, clockwise positive',
                    type=float)
                mount_model = track.model.load_default_model(
                    guide_cam_orientation=Longitude(guide_cam_orientation *
                                                    u.deg))

    if 'mount_model' not in locals():
        print(
            'Aborting: No model could be loaded. To refresh stored model run align program.'
        )
        sys.exit(1)

    # Create object with base type TelescopeMount
    mount = mounts.make_mount_from_args(args)

    telem_logger = telem.make_telem_logger_from_args(args)

    target = targets.make_target_from_args(
        args,
        mount,
        mount_model,
        MeridianSide[args.meridian_side.upper()],
        telem_logger=telem_logger,
    )

    tracker = Tracker(
        mount=mount,
        mount_model=mount_model,
        target=target,
        telem_logger=telem_logger,
    )

    try:
        laser_pointer = laser.make_laser_from_args(args)
    except OSError:
        print('Could not connect to laser pointer FTDI device.')
        laser_pointer = None

    telem_sources = {}
    try:
        # Create gamepad object and register callback
        game_pad = Gamepad()
        if laser_pointer is not None:
            game_pad.register_callback('BTN_SOUTH', laser_pointer.set)
        tracker.register_callback(gamepad_callback)
        telem_sources['gamepad'] = game_pad
        print('Gamepad found and registered.')
    except RuntimeError:
        print('No gamepads found.')

    if telem_logger is not None:
        telem_logger.register_sources(telem_sources)
        telem_logger.start()

    stopping_conditions = control.make_stop_conditions_from_args(args)
    try:
        tracker.run(stopping_conditions)
    except KeyboardInterrupt:
        print('Got CTRL-C, shutting down...')
    finally:
        # don't rely on destructors to safe mount!
        print('Safing mount...', end='', flush=True)
        if mount.safe():
            print('Mount safed successfully!')
        else:
            print('Warning: Mount may be in an unsafe state!')

        try:
            game_pad.stop()
        except UnboundLocalError:
            pass

        if telem_logger is not None:
            telem_logger.stop()
Exemplo n.º 25
0
    coord_detilt = coord.hcrs.cartesian.transform(_SUN_DETILT_MATRIX)
    return coord_detilt.represent_as(SphericalRepresentation).lon.to('deg')


# J2000.0 epoch
_J2000 = Time('J2000.0', scale='tt')

# One of the two nodes of intersection between the ICRF equator and Sun's equator in HCRS
_NODE = SkyCoord(_SOLAR_NORTH_POLE_HCRS.lon + 90 * u.deg,
                 0 * u.deg,
                 frame='hcrs')

# The longitude in the de-tilted frame of the Sun's prime meridian.
# The IAU (Seidelmann et al. 2007 and later) defines the true longitude of the meridian (i.e.,
# without light travel time to Earth and aberration effects) as 84.176 degrees eastward at J2000.
_DLON_MERIDIAN = Longitude(_detilt_lon(_NODE) + constants.get('W_0'))


@add_common_docstring(**_variables_for_parse_time_docstring())
def L0(time='now',
       light_travel_time_correction=True,
       nearest_point=True,
       aberration_correction=False):
    """
    Return the L0 angle for the Sun at a specified time, which is the apparent Carrington longitude
    of the Sun-disk center as seen from Earth.

    Observer corrections can be disabled, and then this function will instead return the true
    Carrington longitude.

    Parameters
Exemplo n.º 26
0
        
    brightness = str(row[14])
    #print(row[12])

    #account for brightness modifier, if '.' then make a little dimmer, if ':' then make a little brighter
    if row[15] == 'f' :
        brightnessFixed = float(brightness)+.3
    elif row[15] == 'b' :
        brightnessFixed = float(brightness)-.3
    else :
        brightnessFixed = float(brightness)
    #brightnessFixed = brightness.translate(None, string.punctuation)

    # Longitudes are measured as degrees from a zodic sign, which is in column [7] of the data
    
    ra = Longitude(((row[8])*30+row[9],row[10]), unit=u.deg)
    dec = Latitude((signLat*row[11],row[12]), unit=u.deg)
    
    #The Equinox of 1601 is chosen for the Tycho Data Set.
    
    object = SkyCoord(ra,dec,distance=10*u.pc, frame='geocentrictrueecliptic', equinox='+01437-01-01T12:00:00.0')

    astar = " "+str(object.galactic.cartesian.x.value)+" "+ \
          str(object.galactic.cartesian.y.value)+" "+ \
          str(object.galactic.cartesian.z.value)+" "+ \
          str(.5)+" "+\
          str(brightnessFixed)+" "+\
          str(brightnessFixed)+" "+\
          str(brightnessFixed)+" "
    
    astarLabel = " "+str(object.galactic.cartesian.x.value)+" "+ \
Exemplo n.º 27
0
    def prepare_plot(self,
                     cats=None,
                     mnts=None,
                     imgs=None,
                     nmls=None,
                     selected=None,
                     model=None):
        stars = list()
        for i, ct in enumerate(cats):
            if not i in selected:
                #self.lg.debug('star: {} dropped'.format(i))
                continue

            mt = mnts[i]  # readability
            mts = mt.represent_as(SphericalRepresentation)
            # ToDo may not the end of the story
            cts = ct.represent_as(SphericalRepresentation)
            df_lon = Longitude(cts.lon.radian - mts.lon.radian,
                               u.radian,
                               wrap_angle=Angle(np.pi, u.radian))
            df_lat = Latitude(cts.lat.radian - mts.lat.radian, u.radian)
            #print(df_lat,df_lon)
            #if df_lat.radian < 0./60./180.*np.pi:
            #  pass
            #elif df_lat.radian > 20./60./180.*np.pi:
            #  pass
            #else:
            #  continue
            #  residuum: difference st.cats(fit corrected) - st.star
            #
            res_lon = Longitude(float(
                model.d_lon(cts.lon.radian, cts.lat.radian,
                            cts.lon.radian - mts.lon.radian)),
                                u.radian,
                                wrap_angle=Angle(np.pi, u.radian))

            res_lat = Latitude(
                float(
                    model.d_lat(cts.lon.radian, cts.lat.radian,
                                cts.lat.radian - mts.lat.radian)), u.radian)

            try:
                image_fn = imgs[i]
            except:
                image_fn = 'no image file'
            try:
                nml_id = nmls[i]
            except:
                nml_id = 'no nml_id'
            st = Point(
                cat_lon=cts.lon,
                cat_lat=cts.lat,
                mnt_lon=mts.lon,
                mnt_lat=mts.lat,
                df_lat=df_lat,
                df_lon=df_lon,
                res_lat=res_lat,
                res_lon=res_lon,
                image_fn=image_fn,
                nml_id=nml_id,
            )
            stars.append(st)

        return stars
Exemplo n.º 28
0
def rot_hpc(x, y, tstart, tend, frame_time='synodic', rot_type='howard', **kwargs):
    """Given a location on the Sun referred to using the Helioprojective
    Cartesian co-ordinate system (typically quoted in the units of arcseconds)
    use the solar rotation profile to find that location at some later or
    earlier time.  Note that this function assumes that the data was observed
    from the Earth or near Earth vicinity.  Specifically, data from SOHO and
    STEREO observatories are not supported.  Note also that the function does
    NOT use solar B0 and L0 values provided in source FITS files - these
    quantities are calculated.

    Parameters
    ----------
    x : `~astropy.units.Quantity`
        Helio-projective x-co-ordinate in arcseconds (can be an array).

    y : `~astropy.units.Quantity`
        Helio-projective y-co-ordinate in arcseconds (can be an array).

    tstart : `sunpy.time.time`
        date/time to which x and y are referred.

    tend : `sunpy.time.time`
    date/time at which x and y will be rotated to.

    rot_type : {'howard' | 'snodgrass' | 'allen'}
        | howard: Use values for small magnetic features from Howard et al.
        | snodgrass: Use Values from Snodgrass et. al
        | allen: Use values from Allen, Astrophysical Quantities, and simpler
          equation.

    frame_time: {'sidereal' | 'synodic'}
        Choose type of day time reference frame.

    Returns
    -------
    x : `~astropy.units.Quantity`
        Rotated helio-projective x-co-ordinate in arcseconds (can be an array).

    y : `~astropy.units.Quantity`
        Rotated helio-projective y-co-ordinate in arcseconds (can be an array).

    Examples
    --------
    >>> import astropy.units as u
    >>> from sunpy.physics.transforms.differential_rotation import rot_hpc
    >>> rot_hpc( -570 * u.arcsec, 120 * u.arcsec, '2010-09-10 12:34:56', '2010-09-10 13:34:56')
    (<Angle -562.9105822671319 arcsec>, <Angle 119.31920621992195 arcsec>)

    Notes
    -----
    SSWIDL code equivalent: http://hesperia.gsfc.nasa.gov/ssw/gen/idl/solar/rot_xy.pro .
    The function rot_xy uses arcmin2hel.pro and hel2arcmin.pro to implement the
    same functionality as this function.  These two functions seem to perform
    inverse operations of each other to a high accuracy.  The corresponding
    equivalent functions here are convert_hpc_hg and convert_hg_hpc
    respectively. These two functions seem to perform inverse
    operations of each other to a high accuracy.  However, the values
    returned by arcmin2hel.pro are slightly different from those provided
    by convert_hpc_hg.  This leads to very slightly different results from
    rot_hpc compared to rot_xy.
    """

    # must have pairs of co-ordinates
    if np.array(x).shape != np.array(y).shape:
        raise ValueError('Input co-ordinates must have the same shape.')

    # Make sure we have enough time information to perform a solar differential
    # rotation
    # Start time
    dstart = parse_time(tstart)
    dend = parse_time(tend)
    interval = (dend - dstart).total_seconds() * u.s

    # Get the Sun's position from the vantage point at the start time
    vstart = kwargs.get("vstart", _calc_P_B0_SD(dstart))
    # Compute heliographic co-ordinates - returns (longitude, latitude). Points
    # off the limb are returned as nan
    longitude, latitude = convert_hpc_hg(x.to(u.arcsec).value,
                                         y.to(u.arcsec).value,
                                         b0_deg=vstart["b0"].to(u.deg).value,
                                         l0_deg=vstart["l0"].to(u.deg).value, 
                                         dsun_meters=(constants.au * sun.sunearth_distance(t=dstart)).value,
                                         angle_units='arcsec')
    longitude = Longitude(longitude, u.deg)
    latitude = Angle(latitude, u.deg)
    # Compute the differential rotation
    drot = diff_rot(interval, latitude, frame_time=frame_time,
                    rot_type=rot_type)

    # Convert back to heliocentric cartesian in units of arcseconds
    vend = kwargs.get("vend", _calc_P_B0_SD(dend))

    # It appears that there is a difference in how the SSWIDL function
    # hel2arcmin and the sunpy function below performs this co-ordinate
    # transform.
    newx, newy = convert_hg_hpc(longitude.to(u.deg).value + drot.to(u.deg).value,
                                latitude.to(u.deg).value,
                                b0_deg=vend["b0"].to(u.deg).value,
                                l0_deg=vend["l0"].to(u.deg).value,
                                dsun_meters=(constants.au * sun.sunearth_distance(t=dend)).value,
                                occultation=False)
    newx = Angle(newx, u.arcsec)
    newy = Angle(newy, u.arcsec)
    return newx.to(u.arcsec), newy.to(u.arcsec)
Exemplo n.º 29
0
 def __init__(self, lon_0, lat_0, sigma):
     self.parameters = Parameters([
         Parameter("lon_0", Longitude(lon_0)),
         Parameter("lat_0", Latitude(lat_0)),
         Parameter("sigma", Angle(sigma), min=0),
     ])
Exemplo n.º 30
0
def test_array(seconds_per_day):
    rot = diff_rot(10 * seconds_per_day, np.linspace(-70, 70, 2) * u.deg)
    assert_quantity_allclose(rot, Longitude(np.array([110.2725,  110.2725]) * u.deg), rtol=1e-3)
Exemplo n.º 31
0
 def __init__(self, lon_0, lat_0):
     self.parameters = Parameters([
         Parameter("lon_0", Longitude(lon_0)),
         Parameter("lat_0", Latitude(lat_0))
     ])
Exemplo n.º 32
0
def diff_rot(duration: u.s,
             latitude: u.deg,
             rot_type='howard',
             frame_time='sidereal'):
    """
    This function computes the change in longitude over days in degrees.

    Parameters
    -----------
    duration : `~astropy.units.Quantity`
        Number of seconds to rotate over.
    latitude : `~astropy.units.Quantity`
        heliographic coordinate latitude in Degrees.
    rot_type : `str`
        The differential rotation model to use.

        One of:

        | ``howard`` : Use values from Howard et al. (1990)
        | ``snodgrass`` : Use values from Snodgrass et. al. (1983)
        | ``allen`` : Use values from Allen's Astrophysical Quantities, and simpler equation.

    frame_time : `str`
        One of : ``'sidereal'`` or  ``'synodic'``. Choose 'type of day' time reference frame.

    Returns
    -------
    longitude_delta : `~astropy.units.Quantity`
        The change in longitude over days (units=degrees)

    References
    ----------

    * `IDL code equivalent <https://hesperia.gsfc.nasa.gov/ssw/gen/idl/solar/diff_rot.pro>`__
    * `Solar surface velocity fields determined from small magnetic features (Howard et al. 1990) <https://doi.org/10.1007/BF00156795>`__
    * `A comparison of differential rotation measurements (Beck 2000, includes Snodgrass values) <https://doi.org/10.1023/A:1005226402796>`__

    Examples
    --------

    Default rotation calculation over two days at 30 degrees latitude:

    >>> import numpy as np
    >>> import astropy.units as u
    >>> from sunpy.physics.differential_rotation import diff_rot
    >>> rotation = diff_rot(2 * u.day, 30 * u.deg)

    Default rotation over two days for a number of latitudes:

    >>> rotation = diff_rot(2 * u.day, np.linspace(-70, 70, 20) * u.deg)

    With rotation type 'allen':

    >>> rotation = diff_rot(2 * u.day, np.linspace(-70, 70, 20) * u.deg, 'allen')
    """

    latitude = latitude.to(u.deg)

    sin2l = (np.sin(latitude))**2
    sin4l = sin2l**2

    rot_params = {
        'howard': [2.894, -0.428, -0.370] * u.urad / u.second,
        'snodgrass': [2.851, -0.343, -0.474] * u.urad / u.second,
        'allen': [14.44, -3.0, 0] * u.deg / u.day
    }

    if rot_type not in ['howard', 'allen', 'snodgrass']:
        raise ValueError("rot_type must equal one of "
                         "{{ {} }}".format(" | ".join(rot_params.keys())))

    A, B, C = rot_params[rot_type]

    # This calculation of the rotation assumes a sidereal frame time.
    rotation = (A + B * sin2l + C * sin4l) * duration

    # Applying this correction assumes that the observer is on the Earth,
    # and that the Earth is at the same distance from the Sun at all times
    # during the year.
    if frame_time == 'synodic':
        rotation -= 0.9856 * u.deg / u.day * duration

    return Longitude(rotation.to(u.deg))
Exemplo n.º 33
0
def healpix_to_lonlat(healpix_index, nside, dx=None, dy=None, order='ring'):
    """
    Convert HEALPix indices (optionally with offsets) to longitudes/latitudes.

    If no offsets (``dx`` and ``dy``) are provided, the coordinates will default
    to those at the center of the HEALPix pixels.

    Parameters
    ----------
    healpix_index : int or `~numpy.ndarray`
        HEALPix indices (as a scalar or array)
    nside : int
        Number of pixels along the side of each of the 12 top-level HEALPix tiles
    dx, dy : float or `~numpy.ndarray`, optional
        Offsets inside the HEALPix pixel, which must be in the range [0:1],
        where 0.5 is the center of the HEALPix pixels (as scalars or arrays)
    order : { 'nested' | 'ring' }, optional
        Order of HEALPix pixels

    Returns
    -------
    lon : :class:`~astropy.coordinates.Longitude`
        The longitude values
    lat : :class:`~astropy.coordinates.Latitude`
        The latitude values
    """

    if (dx is None and dy is not None) or (dx is not None and dy is None):
        raise ValueError('Either both or neither dx and dy must be specified')

    healpix_index = np.asarray(healpix_index, dtype=np.int64)

    if dx is None and dy is not None:
        dx = 0.5
    elif dx is not None and dy is None:
        dy = 0.5

    if dx is not None:
        dx = np.asarray(dx, dtype=np.float)
        dy = np.asarray(dy, dtype=np.float)
        _validate_offset('x', dx)
        _validate_offset('y', dy)
        healpix_index, dx, dy = np.broadcast_arrays(healpix_index, dx, dy)
        dx = dx.ravel()
        dy = dy.ravel()

    shape = healpix_index.shape
    healpix_index = healpix_index.ravel()
    nside = int(nside)

    _validate_healpix_index('healpix_index', healpix_index, nside)
    _validate_nside(nside)
    order = _validate_order(order)

    if dx is None:
        lon, lat = core_cython.healpix_to_lonlat(healpix_index, nside, order)
    else:
        lon, lat = core_cython.healpix_with_offset_to_lonlat(healpix_index, dx, dy, nside, order)

    lon = Longitude(lon, unit=u.rad, copy=False)
    lat = Latitude(lat, unit=u.rad, copy=False)

    return _restore_shape(lon, lat, shape=shape)
Exemplo n.º 34
0
    sc,
    'scc':
    scc,
    'scd':
    SkyCoord([1, 2], [3, 4], [5, 6],
             unit='deg,deg,m',
             frame='fk4',
             obstime=['J1990.5'] * 2),
    'x': [1, 2] * u.m,
    'qdb': [10, 20] * u.dB(u.mW),
    'qdex': [4.5, 5.5] * u.dex(u.cm / u.s**2),
    'qmag': [21, 22] * u.ABmag,
    'lat':
    Latitude([1, 2] * u.deg),
    'lon':
    Longitude([1, 2] * u.deg, wrap_angle=180. * u.deg),
    'ang':
    Angle([1, 2] * u.deg),
    'el':
    el,
    'sr':
    sr,
    'cr':
    cr,
    'sd':
    sd,
    'srd':
    srd,
    # 'nd': NdarrayMixin(el)  # not supported yet
}
Exemplo n.º 35
0
def doTest():
    print(colored('Testing Coordinates Module', 'magenta'))

    print(colored('Testing Ra', 'magenta'))
    print(colored('Testing Default Constructor', 'cyan'))
    ra = NumCpp.RaDouble()
    print(colored('\tPASS', 'green'))

    print(colored('Testing Degree Constructor', 'cyan'))
    randDegrees = np.random.rand(1).item() * 360
    ra = NumCpp.RaDouble(randDegrees)
    raPy = Longitude(randDegrees, unit=u.deg)
    if (round(ra.degrees(), 9) == round(randDegrees, 9) and
        ra.hours() == raPy.hms.h and
        ra.minutes() == raPy.hms.m and
        round(ra.seconds(), 9) == round(raPy.hms.s, 9) and
        round(ra.radians(), 9) == round(np.deg2rad(randDegrees), 9)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing hms Constructor', 'cyan'))
    hours = np.random.randint(0, 24, [1,], dtype=np.uint8).item()
    minutes = np.random.randint(0, 60, [1, ], dtype=np.uint8).item()
    seconds = np.random.rand(1).astype(np.float32).item() * 60
    ra = NumCpp.RaDouble(hours, minutes, seconds)
    degreesPy = (hours + minutes / 60 + seconds / 3600) * 15
    if (round(ra.degrees(), 9) == round(degreesPy, 9) and
        ra.hours() == hours and
        ra.minutes() == minutes and
        round(ra.seconds(), 9) == round(seconds, 9) and
        round(ra.radians(), 9) == round(np.deg2rad(degreesPy), 9)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing astype', 'cyan'))
    raF = ra.asFloat()
    if (round(ra.degrees(), 4) == round(raF.degrees(), 4) and
        ra.hours() == raF.hours() and
        ra.minutes() == raF.minutes() and
        round(ra.seconds(), 4) == round(raF.seconds(), 4) and
        round(ra.radians(), 4) == round(raF.radians(), 4)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing equality operator', 'cyan'))
    ra2 = NumCpp.RaDouble(ra)
    if ra == ra2:
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing not equality operator', 'cyan'))
    randDegrees = np.random.rand(1).item() * 360
    ra2 = NumCpp.RaDouble(randDegrees)
    if ra != ra2:
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing print', 'cyan'))
    ra.print()
    print(colored('\tPASS', 'green'))

    print(colored('Testing Dec', 'magenta'))
    print(colored('Testing Default Constructor', 'cyan'))
    dec = NumCpp.DecDouble()
    print(colored('\tPASS', 'green'))

    print(colored('Testing Degree Constructor', 'cyan'))
    randDegrees = np.random.rand(1).item() * 180 - 90
    dec = NumCpp.DecDouble(randDegrees)
    decPy = Latitude(randDegrees, unit=u.deg)
    sign = NumCpp.Sign.NEGATIVE if randDegrees < 0 else NumCpp.Sign.POSITIVE
    if (round(dec.degrees(), 8) == round(randDegrees, 8) and
        dec.sign() == sign and
        dec.degreesWhole() == abs(decPy.dms.d) and
        dec.minutes() == abs(decPy.dms.m) and
        round(dec.seconds(), 8) == round(abs(decPy.dms.s), 8) and
        round(dec.radians(), 8) == round(np.deg2rad(randDegrees), 8)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing dms Constructor', 'cyan'))
    sign = NumCpp.Sign.POSITIVE if np.random.randint(-1, 1) == 0 else NumCpp.Sign.NEGATIVE
    degrees = np.random.randint(0, 91, [1, ], dtype=np.uint8).item()
    minutes = np.random.randint(0, 60, [1, ], dtype=np.uint8).item()
    seconds = np.random.rand(1).astype(np.float32).item() * 60
    dec = NumCpp.DecDouble(sign, degrees, minutes, seconds)
    degreesPy = degrees + minutes / 60 + seconds / 3600
    if sign == NumCpp.Sign.NEGATIVE:
        degreesPy *= -1
    if (dec.sign() == sign and
        round(dec.degrees(), 9) == round(degreesPy, 9) and
        dec.degreesWhole() == degrees and
        dec.minutes() == minutes and
        round(dec.seconds(), 9) == round(seconds, 9) and
        round(dec.radians(), 8) == round(np.deg2rad(degreesPy), 8)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing astype', 'cyan'))
    decF = dec.asFloat()
    if (round(dec.degrees(), 4) == round(decF.degrees(), 4) and
        dec.sign() == decF.sign() and
        dec.degreesWhole() == decF.degreesWhole() and
        dec.minutes() == decF.minutes() and
        round(dec.seconds(), 4) == round(decF.seconds(), 4) and
        round(dec.radians(), 4) == round(decF.radians(), 4)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing equality operator', 'cyan'))
    dec2 = NumCpp.DecDouble(dec)
    if dec == dec2:
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing not equality operator', 'cyan'))
    randDegrees = np.random.rand(1).item() * 180 - 90
    dec2 = NumCpp.DecDouble(randDegrees)
    if dec != dec2:
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing print', 'cyan'))
    dec.print()
    print(colored('\tPASS', 'green'))

    print(colored('Testing Coordinate', 'magenta'))
    print(colored('Testing Default Constructor', 'cyan'))
    coord = NumCpp.CoordinateDouble()
    print(colored('\tPASS', 'green'))

    print(colored('Testing Degree Constructor', 'cyan'))
    raDegrees = np.random.rand(1).item() * 360
    ra = NumCpp.RaDouble(raDegrees)
    decDegrees = np.random.rand(1).item() * 180 - 90
    dec = NumCpp.DecDouble(decDegrees)

    pyCoord = SkyCoord(raDegrees, decDegrees, unit=u.deg)
    cCoord = NumCpp.CoordinateDouble(raDegrees, decDegrees)
    if (cCoord.ra() == ra and
        cCoord.dec() == dec and
        round(cCoord.x(), 10) == round(pyCoord.cartesian.x.value, 10) and
        round(cCoord.y(), 10) == round(pyCoord.cartesian.y.value, 10) and
        round(cCoord.z(), 10) == round(pyCoord.cartesian.z.value, 10)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing Ra/Dec Constructor', 'cyan'))
    raDegrees = np.random.rand(1).item() * 360
    ra = NumCpp.RaDouble(raDegrees)
    decDegrees = np.random.rand(1).item() * 180 - 90
    dec = NumCpp.DecDouble(decDegrees)

    pyCoord = SkyCoord(raDegrees, decDegrees, unit=u.deg)
    cCoord = NumCpp.CoordinateDouble(ra, dec)
    if (cCoord.ra() == ra and
        cCoord.dec() == dec and
        round(cCoord.x(), 10) == round(pyCoord.cartesian.x.value, 10) and
        round(cCoord.y(), 10) == round(pyCoord.cartesian.y.value, 10) and
        round(cCoord.z(), 10) == round(pyCoord.cartesian.z.value, 10)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing x/y/z Constructor', 'cyan'))
    raDegrees = np.random.rand(1).item() * 360
    ra = NumCpp.RaDouble(raDegrees)
    decDegrees = np.random.rand(1).item() * 180 - 90
    dec = NumCpp.DecDouble(decDegrees)
    pyCoord = SkyCoord(raDegrees, decDegrees, unit=u.deg)
    cCoord = NumCpp.CoordinateDouble(pyCoord.cartesian.x.value, pyCoord.cartesian.y.value, pyCoord.cartesian.z.value)
    if (round(cCoord.ra().degrees(), 9) == round(ra.degrees(), 9) and
        round(cCoord.dec().degrees(), 9) == round(dec.degrees(), 9) and
        round(cCoord.x(), 9) == round(pyCoord.cartesian.x.value, 9) and
        round(cCoord.y(), 9) == round(pyCoord.cartesian.y.value, 9) and
        round(cCoord.z(), 9) == round(pyCoord.cartesian.z.value, 9)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing NdArray Constructor', 'cyan'))
    raDegrees = np.random.rand(1).item() * 360
    ra = NumCpp.RaDouble(raDegrees)
    decDegrees = np.random.rand(1).item() * 180 - 90
    dec = NumCpp.DecDouble(decDegrees)
    pyCoord = SkyCoord(raDegrees, decDegrees, unit=u.deg)
    vec = np.asarray([pyCoord.cartesian.x.value, pyCoord.cartesian.y.value, pyCoord.cartesian.z.value])
    cVec = NumCpp.NdArray(1, 3)
    cVec.setArray(vec)
    cCoord = NumCpp.CoordinateDouble(cVec)
    if (round(cCoord.ra().degrees(), 9) == round(ra.degrees(), 9) and
        round(cCoord.dec().degrees(), 9) == round(dec.degrees(), 9) and
        round(cCoord.x(), 9) == round(pyCoord.cartesian.x.value, 9) and
        round(cCoord.y(), 9) == round(pyCoord.cartesian.y.value, 9) and
        round(cCoord.z(), 9) == round(pyCoord.cartesian.z.value, 9)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing hms/dms Constructor', 'cyan'))
    raHours = np.random.randint(0, 24, [1,], dtype=np.uint8).item()
    raMinutes = np.random.randint(0, 60, [1, ], dtype=np.uint8).item()
    raSeconds = np.random.rand(1).astype(np.float32).item() * 60
    raDegreesPy = (raHours + raMinutes / 60 + raSeconds / 3600) * 15

    decSign = NumCpp.Sign.POSITIVE if np.random.randint(-1, 1) == 0 else NumCpp.Sign.NEGATIVE
    decDegrees = np.random.randint(0, 91, [1, ], dtype=np.uint8).item()
    decMinutes = np.random.randint(0, 60, [1, ], dtype=np.uint8).item()
    decSeconds = np.random.rand(1).astype(np.float32).item() * 60
    decDegreesPy = decDegrees + decMinutes / 60 + decSeconds / 3600
    if decSign == NumCpp.Sign.NEGATIVE:
        decDegreesPy *= -1

    cCoord = NumCpp.CoordinateDouble(raHours, raMinutes, raSeconds, decSign, decDegrees, decMinutes, decSeconds)
    cRa = cCoord.ra()
    cDec = cCoord.dec()
    pyCoord = SkyCoord(raDegreesPy, decDegreesPy, unit=u.deg)
    if (round(cRa.degrees(), 9) == round(raDegreesPy, 9) and
        cRa.hours() == raHours and
        cRa.minutes() == raMinutes and
        round(cRa.seconds(), 9) == round(raSeconds, 9) and
        cDec.sign() == decSign and
        round(cDec.degrees(), 9) == round(decDegreesPy, 9) and
        cDec.degreesWhole() == decDegrees and
        cDec.minutes() == decMinutes and
        round(cDec.seconds(), 9) == round(decSeconds, 9) and
        round(cCoord.x(), 9) == round(pyCoord.cartesian.x.value, 9) and
        round(cCoord.y(), 9) == round(pyCoord.cartesian.y.value, 9) and
        round(cCoord.z(), 9) == round(pyCoord.cartesian.z.value, 9)):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing equality operator', 'cyan'))
    cCoord2 = NumCpp.CoordinateDouble(cCoord)
    if cCoord2 == cCoord:
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing not equality operator', 'cyan'))
    raDegrees = np.random.rand(1).item() * 360
    decDegrees = np.random.rand(1).item() * 180 - 90
    cCoord2 = NumCpp.CoordinateDouble(raDegrees, decDegrees)
    if cCoord2 != cCoord:
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing xyz', 'cyan'))
    xyz = [cCoord.x(), cCoord.y(), cCoord.z()]
    if np.array_equal(cCoord.xyz().getNumpyArray().flatten(), xyz):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing degreeSeperation Coordinate', 'cyan'))
    pyCoord2 = SkyCoord(cCoord2.ra().degrees(), cCoord2.dec().degrees(), unit=u.deg)
    cDegSep = cCoord.degreeSeperation(cCoord2)
    pyDegSep = pyCoord.separation(pyCoord2).value
    if round(cDegSep, 9) == round(pyDegSep, 9):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing radianSeperation Coordinate', 'cyan'))
    cRadSep = cCoord.radianSeperation(cCoord2)
    pyRadSep = np.deg2rad(pyDegSep)
    if round(cRadSep, 9) == round(pyRadSep, 9):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing degreeSeperation Vector', 'cyan'))
    vec2 = np.asarray([pyCoord2.cartesian.x, pyCoord2.cartesian.y, pyCoord2.cartesian.z])
    cArray = NumCpp.NdArray(1, 3)
    cArray.setArray(vec2)
    cDegSep = cCoord.degreeSeperation(cArray)
    if round(cDegSep, 9) == round(pyDegSep, 9):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing radianSeperation Vector', 'cyan'))
    cArray = NumCpp.NdArray(1, 3)
    cArray.setArray(vec2)
    cDegSep = cCoord.radianSeperation(cArray)
    if round(cDegSep, 9) == round(pyRadSep, 9):
        print(colored('\tPASS', 'green'))
    else:
        print(colored('\tFAIL', 'red'))

    print(colored('Testing print', 'cyan'))
    cCoord.print()
    print(colored('\tPASS', 'green'))
Exemplo n.º 36
0
def add_wcs_coordinates(objects, catParNames, catParFormt, catParUnits, Parameters):
	try:
		hdulist = fits.open(Parameters["import"]["inFile"])
		header = hdulist[0].header
		hdulist.close()
		
		# Fix headers where "per second" is written "/S" instead of "/s"
		# (assuming they mean "per second" and not "per Siemens").
		if "cunit3" in header and "/S" in header["cunit3"]:
			err.warning("Converting '/S' to '/s' in CUNIT3.")
			header["cunit3"] = header["cunit3"].replace("/S","/s")
		
		# Check if there is a Nmap/GIPSY FITS header keyword value present
		gipsyKey = [k for k in ["FREQ-OHEL", "FREQ-OLSR", "FREQ-RHEL", "FREQ-RLSR"] if (k in [header[key] for key in header if ("CTYPE" in key)])]
		if gipsyKey:
			err.message("GIPSY header found. Trying to convert to FITS standard.")
			from astropy.wcs import Wcsprm
			header = fix_gipsy_header(header)
			wcsin = Wcsprm(str(header))
			wcsin.sptr("VOPT-F2W")
			#if header["naxis"] == 4:
			#	objects = np.concatenate((objects, wcsin.p2s(np.concatenate((objects[:, catParNames.index("x"):catParNames. index("x") + 3], np.zeros((objects.shape[0], 1))), axis=1), 0)["world"][:,:-1]), axis=1)
			#else:
			#	objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index("x"):catParNames.index("x") + 3], 0)["world"]), axis=1)
			objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index("x"):catParNames.index("x") + 3], 0)["world"]), axis=1)
			catParUnits = tuple(list(catParUnits) + [str(cc).replace(" ", "") for cc in wcsin.cunit])
			catParNames = tuple(list(catParNames) + [(cc.split("--")[0]).lower() for cc in wcsin.ctype])
			catParFormt = tuple(list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])
		
		else:
			# Constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
			rafound = 0
			for kk in range(header["naxis"]):
				if header["ctype1"][:2] == "RA":
					rafound = 1
					break
			if rafound:
				if header["crval%i" % (kk + 1)] < 0:
					err.warning("Adding 360 deg to RA reference value.")
					header["crval%i" % (kk + 1)] += 360
				elif header["crval%i" % (kk + 1)] > 360:
					err.warning("Subtracting 360 deg from RA reference value.")
					header["crval%i" % (kk + 1)] -= 360
			
			#if header["naxis"] == 4: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL, wcs.WCSSUB_STOKES])
			#else: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
			wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
			xyz = objects[:, catParNames.index("x"):catParNames.index("x") + 3].astype(float)
			if "cellscal" in header and header["cellscal"] == "1/F":
				err.warning(
					"CELLSCAL keyword with value of 1/F found.\n"
					"Will account for varying pixel scale in WCS coordinate calculation.")
				x0, y0 = header["crpix1"] - 1, header["crpix2"] - 1
				# Will calculate the pixscale factor of each channel as:
				# pixscale = ref_frequency / frequency
				if header["ctype3"] == "VELO-HEL":
					pixscale = (1 - header["crval3"] / scipy.constants.c) / (1 - (((xyz[:, 2] + 1) - header["crpix3"]) * header["cdelt3"] + header["crval3"]) / scipy.constants.c)
				else:
					err.warning("Cannot convert 3rd axis coordinates to frequency. Ignoring the effect of CELLSCAL = 1/F.")
					pixscale = 1.0
				xyz[:, 0] = (xyz[:, 0] - x0) * pixscale + x0
				xyz[:, 1] = (xyz[:, 1] - y0) * pixscale + y0
			#if header["naxis"] == 4: objects = np.concatenate((objects, wcsin.wcs_pix2world(np.concatenate((xyz, np.zeros((objects.shape[0], 1))), axis=1), 0)[:, :-1]), axis=1)
			#else: objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
			objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
			catParUnits = tuple(list(catParUnits) + [str(cc).replace(" ", "") for cc in wcsin.wcs.cunit])
			catParNames = tuple(list(catParNames) + [(cc.split("--")[0]).lower() for cc in wcsin.wcs.ctype])
			catParFormt = tuple(list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])
		#if header["naxis"] == 4:
		#	catParUnits = catParUnits[:-1]
		#	catParNames= catParNames[:-1]
		err.message("WCS coordinates added to catalogue.")
		
		# Create IAU-compliant source name:
		# WARNING: This currently assumes a regular, ≥ 2-dim. data cube where the first two axes are longitude and latitude.
		n_src = objects.shape[0]
		n_par = objects.shape[1]
		
		iau_names = np.empty([n_src, 1], dtype=object)
		
		if header["ctype1"][:4] == "RA--":
			# Equatorial coordinates; try to figure out equinox:
			iau_coord = "equ"
			if "equinox" in header:
				if int(header["equinox"]) >= 2000: iau_equinox = "J"
				else: iau_equinox = "B"
			elif "epoch" in header:
				# Assume that EPOCH has been abused to record the equinox:
				if int(header["epoch"]) >= 2000: iau_equinox = "J"
				else: iau_equinox = "B"
			else:
				# Equinox undefined:
				iau_equinox = "X"
		elif header["ctype1"][:4] == "GLON":
			# Galactic coordinates:
			iau_coord = "gal"
			iau_equinox = "G"
		else:
			# Unsupported coordinate system:
			iau_coord = ""
			iau_equinox = ""
		
		for src in xrange(n_src):
			lon = objects[src][n_par - 3]
			lat = objects[src][n_par - 2]
			
			if iau_coord == "equ":
				ra = Longitude(lon, unit=u.deg)
				dec = Latitude(lat, unit=u.deg)
				iau_pos = ra.to_string(unit=u.h, decimal=False, sep="", precision=2, alwayssign=False, pad=True, fields=3)
				iau_pos += dec.to_string(unit=u.deg, decimal=False, sep="", precision=1, alwayssign=True, pad=True, fields=3)
			else:
				iau_pos = "{0:08.4f}".format(lon)
				if lat < 0.0: iau_pos += "-"
				else: iau_pos += "+"
				iau_pos += "{0:07.4f}".format(abs(lat))
			
			iau_names[src][0] = "SoFiA " + iau_equinox + iau_pos
		
		objects = np.concatenate((objects, iau_names), axis = 1)
		catParUnits = tuple(list(catParUnits) + ["-"])
		catParNames = tuple(list(catParNames) + ["name"])
		catParFormt = tuple(list(catParFormt) + ["%30s"])
	except:
		err.warning("WCS conversion of parameters failed.")
	
	return (objects, catParNames, catParFormt, catParUnits)
Exemplo n.º 37
0
def add_wcs_coordinates(objects, catParNames, catParFormt, catParUnits,
                        Parameters):
    try:
        hdulist = fits.open(Parameters["import"]["inFile"])
        header = hdulist[0].header
        hdulist.close()

        # Fix headers where "per second" is written "/S" instead of "/s"
        # (assuming they mean "per second" and not "per Siemens").
        if "cunit3" in header and "/S" in header["cunit3"]:
            err.warning("Converting '/S' to '/s' in CUNIT3.")
            header["cunit3"] = header["cunit3"].replace("/S", "/s")

        # Check if there is a Nmap/GIPSY FITS header keyword value present
        gipsyKey = [
            k for k in ["FREQ-OHEL", "FREQ-OLSR", "FREQ-RHEL", "FREQ-RLSR"]
            if (k in [header[key] for key in header if ("CTYPE" in key)])
        ]
        if gipsyKey:
            err.message(
                "GIPSY header found. Trying to convert to FITS standard.")
            from astropy.wcs import Wcsprm
            header = fix_gipsy_header(header)
            wcsin = Wcsprm(str(header))
            wcsin.sptr("VOPT-F2W")
            #if header["naxis"] == 4:
            #	objects = np.concatenate((objects, wcsin.p2s(np.concatenate((objects[:, catParNames.index("x"):catParNames. index("x") + 3], np.zeros((objects.shape[0], 1))), axis=1), 0)["world"][:,:-1]), axis=1)
            #else:
            #	objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index("x"):catParNames.index("x") + 3], 0)["world"]), axis=1)
            objects = np.concatenate(
                (objects,
                 wcsin.p2s(
                     objects[:,
                             catParNames.index("x"):catParNames.index("x") +
                             3], 0)["world"]),
                axis=1)
            catParUnits = tuple(
                list(catParUnits) +
                [str(cc).replace(" ", "") for cc in wcsin.cunit])
            catParNames = tuple(
                list(catParNames) + [(cc.split("--")[0]).lower()
                                     for cc in wcsin.ctype])
            catParFormt = tuple(
                list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])

        else:
            # Constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
            rafound = 0
            for kk in range(header["naxis"]):
                if header["ctype1"][:2] == "RA":
                    rafound = 1
                    break
            if rafound:
                if header["crval%i" % (kk + 1)] < 0:
                    err.warning("Adding 360 deg to RA reference value.")
                    header["crval%i" % (kk + 1)] += 360
                elif header["crval%i" % (kk + 1)] > 360:
                    err.warning("Subtracting 360 deg from RA reference value.")
                    header["crval%i" % (kk + 1)] -= 360

            #if header["naxis"] == 4: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL, wcs.WCSSUB_STOKES])
            #else: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
            wcsin = wcs.WCS(header,
                            naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
            xyz = objects[:,
                          catParNames.index("x"):catParNames.index("x") +
                          3].astype(float)
            if "cellscal" in header and header["cellscal"] == "1/F":
                err.warning(
                    "CELLSCAL keyword with value of 1/F found.\n"
                    "Will account for varying pixel scale in WCS coordinate calculation."
                )
                x0, y0 = header["crpix1"] - 1, header["crpix2"] - 1
                # Will calculate the pixscale factor of each channel as:
                # pixscale = ref_frequency / frequency
                if header["ctype3"] == "VELO-HEL":
                    pixscale = (1 - header["crval3"] / scipy.constants.c) / (
                        1 - (((xyz[:, 2] + 1) - header["crpix3"]) *
                             header["cdelt3"] + header["crval3"]) /
                        scipy.constants.c)
                else:
                    err.warning(
                        "Cannot convert 3rd axis coordinates to frequency. Ignoring the effect of CELLSCAL = 1/F."
                    )
                    pixscale = 1.0
                xyz[:, 0] = (xyz[:, 0] - x0) * pixscale + x0
                xyz[:, 1] = (xyz[:, 1] - y0) * pixscale + y0
            #if header["naxis"] == 4: objects = np.concatenate((objects, wcsin.wcs_pix2world(np.concatenate((xyz, np.zeros((objects.shape[0], 1))), axis=1), 0)[:, :-1]), axis=1)
            #else: objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
            objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)),
                                     axis=1)
            catParUnits = tuple(
                list(catParUnits) +
                [str(cc).replace(" ", "") for cc in wcsin.wcs.cunit])
            catParNames = tuple(
                list(catParNames) + [(cc.split("--")[0]).lower()
                                     for cc in wcsin.wcs.ctype])
            catParFormt = tuple(
                list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])
        #if header["naxis"] == 4:
        #	catParUnits = catParUnits[:-1]
        #	catParNames= catParNames[:-1]
        err.message("WCS coordinates added to catalogue.")

        # Create IAU-compliant source name:
        # WARNING: This currently assumes a regular, ≥ 2-dim. data cube where the first two axes are longitude and latitude.
        n_src = objects.shape[0]
        n_par = objects.shape[1]

        iau_names = np.empty([n_src, 1], dtype=object)

        if header["ctype1"][:4] == "RA--":
            # Equatorial coordinates; try to figure out equinox:
            iau_coord = "equ"
            if "equinox" in header:
                if int(header["equinox"]) >= 2000: iau_equinox = "J"
                else: iau_equinox = "B"
            elif "epoch" in header:
                # Assume that EPOCH has been abused to record the equinox:
                if int(header["epoch"]) >= 2000: iau_equinox = "J"
                else: iau_equinox = "B"
            else:
                # Equinox undefined:
                iau_equinox = "X"
        elif header["ctype1"][:4] == "GLON":
            # Galactic coordinates:
            iau_coord = "gal"
            iau_equinox = "G"
        else:
            # Unsupported coordinate system:
            iau_coord = ""
            iau_equinox = ""

        for src in xrange(n_src):
            lon = objects[src][n_par - 3]
            lat = objects[src][n_par - 2]

            if iau_coord == "equ":
                ra = Longitude(lon, unit=u.deg)
                dec = Latitude(lat, unit=u.deg)
                iau_pos = ra.to_string(unit=u.h,
                                       decimal=False,
                                       sep="",
                                       precision=2,
                                       alwayssign=False,
                                       pad=True,
                                       fields=3)
                iau_pos += dec.to_string(unit=u.deg,
                                         decimal=False,
                                         sep="",
                                         precision=1,
                                         alwayssign=True,
                                         pad=True,
                                         fields=3)
            else:
                iau_pos = "{0:08.4f}".format(lon)
                if lat < 0.0: iau_pos += "-"
                else: iau_pos += "+"
                iau_pos += "{0:07.4f}".format(abs(lat))

            iau_names[src][0] = "SoFiA " + iau_equinox + iau_pos

        objects = np.concatenate((objects, iau_names), axis=1)
        catParUnits = tuple(list(catParUnits) + ["-"])
        catParNames = tuple(list(catParNames) + ["name"])
        catParFormt = tuple(list(catParFormt) + ["%30s"])
    except:
        err.warning("WCS conversion of parameters failed.")

    return (objects, catParNames, catParFormt, catParUnits)