Example #1
0
def airmassPP(zangle):
    """
    Calculate airmass for plane parallel atmosphere.
    
    Parameters
    ----------
    zangle : float or array
        The zenith angle in degrees.
    
    Returns
    -------
    Airmass : float or array
        The airmass assuming a plane parallel
        atmosphere.
  """
    return 1.0 / np.cos(PC.degtorad(zangle))
Example #2
0
def airmassPP(zangle):
  """
    Calculate airmass for plane parallel atmosphere.
    
    Parameters
    ----------
    zangle : float or array
        The zenith angle in degrees.
    
    Returns
    -------
    Airmass : float or array
        The airmass assuming a plane parallel
        atmosphere.
  """
  return 1.0/np.cos(PC.degtorad(zangle))
Example #3
0
def airmassSpherical(zangle, obsAltitude, rearth=6371.0, yatm=10.0):
  """
    Calculate the airmass for a given zenith angle and observer altitude.
    
    This routine uses a geometric formula for a homogeneous, spherical
    atmosphere with an elevated observer.
    
    .. note:: In this model, the airmass is *not* necessarily one
              toward the zenith.
    
    Parameters
    ----------
    zangle : float
        Zenith angle of an object in deg.
    obsAltitude :  float
        Elevation of the observer in meter.
    rearth : float, optional
        Earth's radius in km.
    yatm : float, optional
        Height of the atmosphere in km.

    Returns
    -------
    Airmass : float
        The airmass.
  """

  # Convert observer's altitude to km to have
  # consistent units
  obsAltitude = obsAltitude/1000.0
  r = (rearth/yatm)
  y = (obsAltitude/yatm)

  # Find maximal zenith angle 
  zmax = 180.0 - PC.radtodeg(np.arcsin(rearth/(rearth + obsAltitude)))
  if zangle > zmax:
    raise(PE.PyAValError("Zenith angle is too large. The maximum allowed angle is " + str(zmax) + " deg.", \
          solution="Use an angle within the limit. Check observer's altitude."))
  
  # Convert into deg
  zangle = PC.degtorad(zangle)

  return np.sqrt( ( r + y )**2 * np.cos(zangle)**2 + 2.*r*(1.-y) - y**2 + 1.0 ) - \
         (r+y)*np.cos(zangle)
Example #4
0
def airmassSpherical(zangle, obsAltitude, rearth=6371.0, yatm=10.0):
    """
    Calculate the airmass for a given zenith angle and observer altitude.
    
    This routine uses a geometric formula for a homogeneous, spherical
    atmosphere with an elevated observer.
    
    .. note:: In this model, the airmass is *not* necessarily one
              toward the zenith.
    
    Parameters
    ----------
    zangle : float
        Zenith angle of an object in deg.
    obsAltitude :  float
        Elevation of the observer in meter.
    rearth : float, optional
        Earth's radius in km.
    yatm : float, optional
        Height of the atmosphere in km.

    Returns
    -------
    Airmass : float
        The airmass.
  """

    # Convert observer's altitude to km to have
    # consistent units
    obsAltitude = obsAltitude / 1000.0
    r = (rearth / yatm)
    y = (obsAltitude / yatm)

    # Find maximal zenith angle
    zmax = 180.0 - PC.radtodeg(np.arcsin(rearth / (rearth + obsAltitude)))
    if zangle > zmax:
        raise(PE.PyAValError("Zenith angle is too large. The maximum allowed angle is " + str(zmax) + " deg.", \
              solution="Use an angle within the limit. Check observer's altitude."))

    # Convert into deg
    zangle = PC.degtorad(zangle)

    return np.sqrt( ( r + y )**2 * np.cos(zangle)**2 + 2.*r*(1.-y) - y**2 + 1.0 ) - \
           (r+y)*np.cos(zangle)
Example #5
0
def helcorr(obs_long, obs_lat, obs_alt, ra2000, dec2000, jd, debug=False):
    """
    Calculate barycentric velocity correction.
    
    This function calculates the motion of an observer in
    the direction of a star. In contract to :py:func:`baryvel`
    and :py:func:`baryCorr`, the rotation of the Earth is
    taken into account.
    
    .. note:: This function was ported from the REDUCE IDL package.
              See Piskunov & Valenti 2002, A&A 385, 1095 for a detailed
              description of the package and/or visit
              http://www.astro.uu.se/~piskunov/RESEARCH/REDUCE/
    
    .. warning:: Contrary to the original implementation the longitude
                 increases toward the East and the right ascension is
                 given in degrees instead of hours. The JD is given as is,
                 in particular, nothing needs to be subtracted.
    
    Parameters
    ----------
    obs_long : float
        Longitude of observatory (degrees, **eastern** direction is positive)
    obs_lat : float
        Latitude of observatory [deg]
    obs_alt : float
        Altitude of observatory [m]
    ra2000 : float
        Right ascension of object for epoch 2000.0 [deg]
    dec2000 : float
        Declination of object for epoch 2000.0 [deg]
    jd : float
        Julian date for the middle of exposure.
    
    Returns
    -------
    Barycentric correction : float
        The barycentric correction accounting for the rotation
        of the Earth, the rotation of the Earth's center around
        the Earth-Moon barycenter, and the motion of the Earth-Moon 
        barycenter around the center of the Sun [km/s].
    HJD : float
        Heliocentric Julian date for middle of exposure.

    Notes
    -----

    :IDL REDUCE - Documentation:


    Calculates heliocentric Julian date, barycentric and heliocentric radial
    velocity corrections from:
    
    INPUT:
    <OBSLON> Longitude of observatory (degrees, western direction is positive)
    <OBSLAT> Latitude of observatory (degrees)
    <OBSALT> Altitude of observatory (meters)
    <RA2000> Right ascension of object for epoch 2000.0 (hours)
    <DE2000> Declination of object for epoch 2000.0 (degrees)
    <JD> Julian date for the middle of exposure
    [DEBUG=] set keyword to get additional results for debugging
    
    OUTPUT:
    <CORRECTION> barycentric correction - correction for rotation of earth,
       rotation of earth center about the earth-moon barycenter, earth-moon 
       barycenter about the center of the Sun.
    <HJD> Heliocentric Julian date for middle of exposure
    
    Algorithms used are taken from the IRAF task noao.astutils.rvcorrect
    and some procedures of the IDL Astrolib are used as well.
    Accuracy is about 0.5 seconds in time and about 1 m/s in velocity.
    
    History:
    written by Peter Mittermayer, Nov 8,2003
    2005-January-13   Kudryavtsev   Made more accurate calculation of the sidereal time.
                                    Conformity with MIDAS compute/barycorr is checked.
    2005-June-20      Kochukhov Included precession of RA2000 and DEC2000 to current epoch

"""
    from PyAstronomy.pyaC import degtorad

    # This reverts the original longitude convention. After this,
    # East longitudes are positive
    obs_long = -obs_long

    if jd < 2.4e6:
        PE.warn(
            PE.PyAValError("The given Julian Date (" + str(jd) +
                           ") is exceedingly small. Did you subtract 2.4e6?"))

    # Covert JD to Gregorian calendar date
    xjd = jd

    year, month, day, ut = tuple(daycnv(xjd))

    # Current epoch
    epoch = year + month / 12. + day / 365.

    # Precess ra2000 and dec2000 to current epoch, resulting ra is in degrees
    ra = ra2000
    dec = dec2000
    ra, dec = precess(ra, dec, 2000.0, epoch)

    # Calculate heliocentric julian date
    rjd = jd - 2.4e6
    hjd = helio_jd(rjd, ra, dec) + 2.4e6

    # DIURNAL VELOCITY (see IRAF task noao.astutil.rvcorrect)
    # convert geodetic latitude into geocentric latitude to correct
    # for rotation of earth
    dlat = -(11.*60.+32.743)*np.sin(2.0*degtorad(obs_lat)) \
           +1.1633*np.sin(4.0*degtorad(obs_lat)) - 0.0026*np.sin(6.0*degtorad(obs_lat))
    lat = obs_lat + dlat / 3600.0

    # Calculate distance of observer from earth center
    r = 6378160.0 * (0.998327073+0.001676438*np.cos(2.0*degtorad(lat)) \
       -0.00000351 * np.cos(4.0*degtorad(lat)) + 0.000000008*np.cos(6.0*degtorad(lat))) \
       + obs_alt

    # Calculate rotational velocity (perpendicular to the radius vector) in km/s
    # 23.934469591229 is the sidereal day in hours for 1986
    v = 2. * np.pi * (r / 1000.) / (23.934469591229 * 3600.)

    # Calculating local mean sidereal time (see astronomical almanach)
    tu = (rjd - 51545.0) / 36525.0
    gmst = 6.697374558 + ut + \
          (236.555367908*(rjd-51545.0) + 0.093104*tu**2 - 6.2e-6*tu**3)/3600.0
    lmst = idlMod(gmst - obs_long / 15., 24)

    # Projection of rotational velocity along the line of sight
    vdiurnal = v * np.cos(degtorad(lat)) * np.cos(degtorad(dec)) * np.sin(
        degtorad(ra - lmst * 15))

    # BARICENTRIC and HELIOCENTRIC VELOCITIES
    vh, vb = baryvel(xjd, 0)

    # Project to line of sight
    vbar = vb[0]*np.cos(degtorad(dec))*np.cos(degtorad(ra)) + vb[1]*np.cos(degtorad(dec))*np.sin(degtorad(ra)) + \
           vb[2]*np.sin(degtorad(dec))
    vhel = vh[0]*np.cos(degtorad(dec))*np.cos(degtorad(ra)) + vh[1]*np.cos(degtorad(dec))*np.sin(degtorad(ra)) + \
           vh[2]*np.sin(degtorad(dec))

    # Use barycentric velocity for correction
    corr = (vdiurnal + vbar)

    if debug:
        print('')
        print('----- HELCORR.PRO - DEBUG INFO - START ----')
        print(
            '(obs_long (East positive),obs_lat,obs_alt) Observatory coordinates [deg,m]: ',
            -obs_long, obs_lat, obs_alt)
        print('(ra,dec) Object coordinates (for epoch 2000.0) [deg]: ', ra,
              dec)
        print('(ut) Universal time (middle of exposure) [hrs]: ', ut)
        print('(jd) Julian date (middle of exposure) (JD): ', jd)
        print('(hjd) Heliocentric Julian date (middle of exposure) (HJD): ',
              hjd)
        print('(gmst) Greenwich mean sidereal time [hrs]: ', idlMod(gmst, 24))
        print('(lmst) Local mean sidereal time [hrs]: ', lmst)
        print('(dlat) Latitude correction [deg]: ', dlat)
        print('(lat) Geocentric latitude of observer [deg]: ', lat)
        print('(r) Distance of observer from center of earth [m]: ', r)
        print(
            '(v) Rotational velocity of earth at the position of the observer [km/s]: ',
            v)
        print(
            '(vdiurnal) Projected earth rotation and earth-moon revolution [km/s]: ',
            vdiurnal)
        print('(vbar) Barycentric velocity [km/s]: ', vbar)
        print('(vhel) Heliocentric velocity [km/s]: ', vhel)
        print('(corr) Vdiurnal+vbar [km/s]: ', corr)
        print('----- HELCORR.PRO - DEBUG INFO - END -----')
        print('')

    return corr, hjd
Example #6
0
def helcorr(obs_long, obs_lat, obs_alt, ra2000, dec2000, jd, debug=False):
  """
    Calculate barycentric velocity correction.
    
    This function calculates the motion of an observer in
    the direction of a star. In contract to :py:func:`baryvel`
    and :py:func:`baryCorr`, the rotation of the Earth is
    taken into account.
    
    .. note:: This function was ported from the REDUCE IDL package.
              See Piskunov & Valenti 2002, A&A 385, 1095 for a detailed
              description of the package and/or visit
              http://www.astro.uu.se/~piskunov/RESEARCH/REDUCE/
    
    .. warning:: Contrary to the original implementation the longitude
                 increases toward the East and the right ascension is
                 given in degrees instead of hours. The JD is given as is,
                 in particular, nothing needs to be subtracted.
    
    Parameters
    ----------
    obs_long : float
        Longitude of observatory (degrees, **eastern** direction is positive)
    obs_lat : float
        Latitude of observatory [deg]
    obs_alt : float
        Altitude of observatory [m]
    ra2000 : float
        Right ascension of object for epoch 2000.0 [deg]
    dec2000 : float
        Declination of object for epoch 2000.0 [deg]
    jd : float
        Julian date for the middle of exposure.
    
    Returns
    -------
    Barycentric correction : float
        The barycentric correction accounting for the rotation
        of the Earth, the rotation of the Earth's center around
        the Earth-Moon barycenter, and the motion of the Earth-Moon 
        barycenter around the center of the Sun [km/s].
    HJD : float
        Heliocentric Julian date for middle of exposure.

    Notes
    -----

    :IDL REDUCE - Documentation:


    Calculates heliocentric Julian date, barycentric and heliocentric radial
    velocity corrections from:
    
    INPUT:
    <OBSLON> Longitude of observatory (degrees, western direction is positive)
    <OBSLAT> Latitude of observatory (degrees)
    <OBSALT> Altitude of observatory (meters)
    <RA2000> Right ascension of object for epoch 2000.0 (hours)
    <DE2000> Declination of object for epoch 2000.0 (degrees)
    <JD> Julian date for the middle of exposure
    [DEBUG=] set keyword to get additional results for debugging
    
    OUTPUT:
    <CORRECTION> barycentric correction - correction for rotation of earth,
       rotation of earth center about the earth-moon barycenter, earth-moon 
       barycenter about the center of the Sun.
    <HJD> Heliocentric Julian date for middle of exposure
    
    Algorithms used are taken from the IRAF task noao.astutils.rvcorrect
    and some procedures of the IDL Astrolib are used as well.
    Accuracy is about 0.5 seconds in time and about 1 m/s in velocity.
    
    History:
    written by Peter Mittermayer, Nov 8,2003
    2005-January-13   Kudryavtsev   Made more accurate calculation of the sidereal time.
                                    Conformity with MIDAS compute/barycorr is checked.
    2005-June-20      Kochukhov Included precession of RA2000 and DEC2000 to current epoch

"""
  from PyAstronomy.pyaC import degtorad

  # This reverts the original longitude convention. After this,
  # East longitudes are positive
  obs_long = -obs_long

  if jd < 2.4e6:
    PE.warn(PE.PyAValError("The given Julian Date (" + str(jd) + ") is exceedingly small. Did you subtract 2.4e6?"))

  # Covert JD to Gregorian calendar date
  xjd = jd
  
  year, month, day, ut = tuple(daycnv(xjd))

  # Current epoch
  epoch = year + month/12. + day/365.

  # Precess ra2000 and dec2000 to current epoch, resulting ra is in degrees
  ra = ra2000
  dec = dec2000
  ra, dec = precess(ra, dec, 2000.0, epoch)  

  # Calculate heliocentric julian date
  rjd = jd-2.4e6
  hjd = helio_jd(rjd, ra, dec) + 2.4e6

  # DIURNAL VELOCITY (see IRAF task noao.astutil.rvcorrect)
  # convert geodetic latitude into geocentric latitude to correct
  # for rotation of earth
  dlat = -(11.*60.+32.743)*np.sin(2.0*degtorad(obs_lat)) \
         +1.1633*np.sin(4.0*degtorad(obs_lat)) - 0.0026*np.sin(6.0*degtorad(obs_lat))
  lat = obs_lat + dlat/3600.0

  # Calculate distance of observer from earth center
  r = 6378160.0 * (0.998327073+0.001676438*np.cos(2.0*degtorad(lat)) \
     -0.00000351 * np.cos(4.0*degtorad(lat)) + 0.000000008*np.cos(6.0*degtorad(lat))) \
     + obs_alt

  # Calculate rotational velocity (perpendicular to the radius vector) in km/s
  # 23.934469591229 is the sidereal day in hours for 1986
  v = 2.*np.pi * (r/1000.) / (23.934469591229*3600.)

  # Calculating local mean sidereal time (see astronomical almanach)
  tu = (rjd-51545.0)/36525.0
  gmst = 6.697374558 + ut + \
        (236.555367908*(rjd-51545.0) + 0.093104*tu**2 - 6.2e-6*tu**3)/3600.0
  lmst = idlMod(gmst-obs_long/15, 24)

  # Projection of rotational velocity along the line of sight
  vdiurnal = v*np.cos(degtorad(lat))*np.cos(degtorad(dec))*np.sin(degtorad(ra-lmst*15))

  # BARICENTRIC and HELIOCENTRIC VELOCITIES
  vh, vb = baryvel(xjd,0)

  # Project to line of sight
  vbar = vb[0]*np.cos(degtorad(dec))*np.cos(degtorad(ra)) + vb[1]*np.cos(degtorad(dec))*np.sin(degtorad(ra)) + \
         vb[2]*np.sin(degtorad(dec))
  vhel = vh[0]*np.cos(degtorad(dec))*np.cos(degtorad(ra)) + vh[1]*np.cos(degtorad(dec))*np.sin(degtorad(ra)) + \
         vh[2]*np.sin(degtorad(dec))
  
  # Use barycentric velocity for correction
  corr = (vdiurnal + vbar) 

  if debug:
    print ''
    print '----- HELCORR.PRO - DEBUG INFO - START ----'
    print '(obs_long (East positive),obs_lat,obs_alt) Observatory coordinates [deg,m]: ', -obs_long, obs_lat, obs_alt
    print '(ra,dec) Object coordinates (for epoch 2000.0) [deg]: ', ra,dec
    print '(ut) Universal time (middle of exposure) [hrs]: ', ut
    print '(jd) Julian date (middle of exposure) (JD): ', jd
    print '(hjd) Heliocentric Julian date (middle of exposure) (HJD): ', hjd
    print '(gmst) Greenwich mean sidereal time [hrs]: ', idlMod(gmst, 24)
    print '(lmst) Local mean sidereal time [hrs]: ', lmst
    print '(dlat) Latitude correction [deg]: ', dlat
    print '(lat) Geocentric latitude of observer [deg]: ', lat
    print '(r) Distance of observer from center of earth [m]: ', r
    print '(v) Rotational velocity of earth at the position of the observer [km/s]: ', v
    print '(vdiurnal) Projected earth rotation and earth-moon revolution [km/s]: ', vdiurnal
    print '(vbar) Barycentric velocity [km/s]: ', vbar
    print '(vhel) Heliocentric velocity [km/s]: ', vhel
    print '(corr) Vdiurnal+vbar [km/s]: ', corr
    print '----- HELCORR.PRO - DEBUG INFO - END -----'
    print ''
  
  return corr, hjd
Example #7
0
def positionAngle(ra1, dec1, ra2, dec2, positive=True):
    """
    Compute the position angle.
  
    The position angle is measured from the first position
    from North through East. If the `positive` flag is set
    True (default) the result will be given as an angle from
    0 to 360 degrees. If the flag is set False, the scale is
    -180 to 180 degrees with negative number increasing from
    North through West; note that this is the behavior of
    the posAng IDL routine.
    
    Parameters
    ----------
    ra1 : float
        Right ascension of first object [deg].
    dec1 : float
        Declination of first object [deg].
    ra2 : float
        Right ascension of second object [deg].
    dec2 : float
        Declination of second object [deg].
    positive : boolean, optional
        If True (default), the output will be
        given as an angle between 0 and 360
        degrees. Otherwise, the angle ranges
        from -180 to +180 degrees.
    
    Returns
    -------
    Position angle : float
        The position angle in degrees.
    
  
    Notes
    -----
    
    .. note:: This function was ported from the IDL Astronomy User's Library.
    
    :IDL - Documentation:  
    
     NAME:
           POSANG
     PURPOSE:
           Computes rigorous position angle of source 2 relative to source 1
           
     EXPLANATION:
           Computes the rigorous position angle of source 2 (with given RA, Dec) 
           using source 1 (with given RA, Dec) as the center.
     
     CALLING SEQUENCE:
           POSANG, U, RA1, DC1, RA2, DC2, ANGLE
    
     INPUTS:
           U    -- Describes units of inputs and output:
                   0:  everything radians
                   1:  RAx in decimal hours, DCx in decimal
                           degrees, ANGLE in degrees
           RA1  -- Right ascension of point 1
           DC1  -- Declination of point 1
           RA2  -- Right ascension of point 2
           DC2  -- Declination of point 2
    
       OUTPUTS:
           ANGLE-- Angle of the great circle containing [ra2, dc2] from
                   the meridian containing [ra1, dc1], in the sense north
                   through east rotating about [ra1, dc1].  See U above 
                   for units.
    
       PROCEDURE:
           The "four-parts formula" from spherical trig (p. 12 of Smart's
           Spherical Astronomy or p. 12 of Green' Spherical Astronomy).
    
       EXAMPLE:
           For the star 56 Per, the Hipparcos catalog gives a position of 
           RA = 66.15593384, Dec = 33.94988843 for component A, and 
           RA = 66.15646079, Dec =  33.96100069 for component B.   What is the
           position angle of B relative to A?
    
           IDL> RA1 = 66.15593384/15.d   & DC1 = 33.95988843
           IDL> RA2 = 66.15646079/15.d   & DC2 = 33.96100069
           IDL> posang,1,ra1,dc1,ra2,dc2, ang
                will give the answer of ang = 21.4 degrees
       NOTES:
           (1) If RA1,DC1 are scalars, and RA2,DC2 are vectors, then ANGLE is a
           vector giving the position angle between each element of RA2,DC2 and 
           RA1,DC1.   Similarly, if RA1,DC1 are vectors, and RA2, DC2 are scalars,
           then DIS is a vector giving the position angle of each element of RA1, 
           DC1 and RA2, DC2.    If both RA1,DC1 and RA2,DC2 are vectors then ANGLE 
           is a vector giving the position angle between each element of RA1,DC1 
           and the corresponding element of RA2,DC2.    If then vectors are not the
           same length, then excess elements of the longer one will be ignored.
    
           (2) Note that POSANG is not commutative -- the position angle between
            A and B is theta, then the position angle between B and A is 180+theta 
       PROCEDURE CALLS:
            ISARRAY()
       HISTORY:
           Modified from GCIRC, R. S. Hill, RSTX, 1 Apr. 1998
           Use V6.0 notation W.L. Mar 2011
  """

    # Convert into rad
    rarad1 = pyaC.degtorad(ra1)
    rarad2 = pyaC.degtorad(ra2)
    dcrad1 = pyaC.degtorad(dec1)
    dcrad2 = pyaC.degtorad(dec2)

    radif = rarad2 - rarad1

    angle = arctan2(sin(radif),
                    cos(dcrad1) * tan(dcrad2) - sin(dcrad1) * cos(radif))

    result = pyaC.radtodeg(angle)

    if positive and (result < 0.0):
        result += 360.0

    return result
Example #8
0
def positionAngle(ra1, dec1, ra2, dec2, positive=True):
  """
    Compute the position angle.
  
    The position angle is measured from the first position
    from North through East. If the `positive` flag is set
    True (default) the result will be given as an angle from
    0 to 360 degrees. If the flag is set False, the scale is
    -180 to 180 degrees with negative number increasing from
    North through West; note that this is the behavior of
    the posAng IDL routine.
    
    Parameters
    ----------
    ra1 : float
        Right ascension of first object [deg].
    dec1 : float
        Declination of first object [deg].
    ra2 : float
        Right ascension of second object [deg].
    dec2 : float
        Declination of second object [deg].
    positive : boolean, optional
        If True (default), the output will be
        given as an angle between 0 and 360
        degrees. Otherwise, the angle ranges
        from -180 to +180 degrees.
    
    Returns
    -------
    Position angle : float
        The position angle in degrees.
    
  
    Notes
    -----
    
    .. note:: This function was ported from the IDL Astronomy User's Library.
    
    :IDL - Documentation:  
    
     NAME:
           POSANG
     PURPOSE:
           Computes rigorous position angle of source 2 relative to source 1
           
     EXPLANATION:
           Computes the rigorous position angle of source 2 (with given RA, Dec) 
           using source 1 (with given RA, Dec) as the center.
     
     CALLING SEQUENCE:
           POSANG, U, RA1, DC1, RA2, DC2, ANGLE
    
     INPUTS:
           U    -- Describes units of inputs and output:
                   0:  everything radians
                   1:  RAx in decimal hours, DCx in decimal
                           degrees, ANGLE in degrees
           RA1  -- Right ascension of point 1
           DC1  -- Declination of point 1
           RA2  -- Right ascension of point 2
           DC2  -- Declination of point 2
    
       OUTPUTS:
           ANGLE-- Angle of the great circle containing [ra2, dc2] from
                   the meridian containing [ra1, dc1], in the sense north
                   through east rotating about [ra1, dc1].  See U above 
                   for units.
    
       PROCEDURE:
           The "four-parts formula" from spherical trig (p. 12 of Smart's
           Spherical Astronomy or p. 12 of Green' Spherical Astronomy).
    
       EXAMPLE:
           For the star 56 Per, the Hipparcos catalog gives a position of 
           RA = 66.15593384, Dec = 33.94988843 for component A, and 
           RA = 66.15646079, Dec =  33.96100069 for component B.   What is the
           position angle of B relative to A?
    
           IDL> RA1 = 66.15593384/15.d   & DC1 = 33.95988843
           IDL> RA2 = 66.15646079/15.d   & DC2 = 33.96100069
           IDL> posang,1,ra1,dc1,ra2,dc2, ang
                will give the answer of ang = 21.4 degrees
       NOTES:
           (1) If RA1,DC1 are scalars, and RA2,DC2 are vectors, then ANGLE is a
           vector giving the position angle between each element of RA2,DC2 and 
           RA1,DC1.   Similarly, if RA1,DC1 are vectors, and RA2, DC2 are scalars,
           then DIS is a vector giving the position angle of each element of RA1, 
           DC1 and RA2, DC2.    If both RA1,DC1 and RA2,DC2 are vectors then ANGLE 
           is a vector giving the position angle between each element of RA1,DC1 
           and the corresponding element of RA2,DC2.    If then vectors are not the
           same length, then excess elements of the longer one will be ignored.
    
           (2) Note that POSANG is not commutative -- the position angle between
            A and B is theta, then the position angle between B and A is 180+theta 
       PROCEDURE CALLS:
            ISARRAY()
       HISTORY:
           Modified from GCIRC, R. S. Hill, RSTX, 1 Apr. 1998
           Use V6.0 notation W.L. Mar 2011
  """

  # Convert into rad               
  rarad1 = pyaC.degtorad(ra1)
  rarad2 = pyaC.degtorad(ra2)
  dcrad1 = pyaC.degtorad(dec1)
  dcrad2 = pyaC.degtorad(dec2)

  radif  = rarad2 - rarad1

  angle  = arctan2(sin(radif), cos(dcrad1)*tan(dcrad2)-sin(dcrad1)*cos(radif))

  result = pyaC.radtodeg(angle)
  
  if positive and (result < 0.0):
    result+= 360.0

  return result