Calculate sunrise or sunset based on:
        Parameters:
            jd: Julian Day
            lat: latitude
            lon: longitude
            stage: sunrise or sunset

def _calc(cls, **kwargs):
        """
        Calculate sunrise or sunset based on:
        Parameters:
            jd: Julian Day
            lat: latitude
            lon: longitude
            stage: sunrise or sunset
        """
        zenith = 90.833333 # offical value

        jd = kwargs.get("jd", None)
        lat = kwargs.get("lat", None)
        lon = kwargs.get("lon", None)
        stage = kwargs.get("stage", None)
        if jd is None or stage is None or lat is None or lon is None:
            raise ValueError("Must supply an 'jd', 'lat, 'lon', and 'stage' parameter")

        if stage != SunCycles.RISING and stage != SunCycles.SETTING:
            raise ValueError("'stage' parameter must be %s or %s" % (SunCycles.RISING, SunCycles.SETTING))

        longhr = lon / 15.
        if stage == SunCycles.RISING:
            apx = jd + ( (6 - longhr) / 24 )
        elif stage == SunCycles.SETTING:
            apx = jd + ( (18 - longhr) / 24 )

        sun_mean_anom = ( 0.9856 * apx ) - 3.289 # sun's mean anomaly
        #sun's longitude
        sun_lon = sun_mean_anom + (1.916 * np.sin( np.radians(sun_mean_anom) )) \
                + (0.02 * np.sin( np.radians(2 * sun_mean_anom) )) + 282.634

        if sun_lon > 360:
            sun_lon = sun_lon - 360
        elif sun_lon < 0:
            sun_lon = sun_lon + 360

        right_ascension = np.degrees(np.arctan( 0.91764 * np.tan( np.radians(sun_lon) ) )) # sun's right ascension

        if right_ascension > 360:
            right_ascension = right_ascension - 360
        elif right_ascension < 0:
            right_ascension = right_ascension + 360

        # put sun's right ascension value in the same quadrant as the sun's
        # true longitude
        lQuad = 90. * np.floor(sun_lon / 90.)
        raQuad = 90. * np.floor(right_ascension / 90.)
        right_ascension = right_ascension + ( lQuad - raQuad)
        right_ascension = right_ascension / 15. # Convert to hours

        # Sun's declination
        sinDecl = 0.39782 * np.sin( np.radians(sun_lon) )
        cosDecl = np.cos( np.arcsin( sinDecl ) )

        # Sun's local hour angle
        cosHr = (np.cos( np.radians(zenith) ) - ( sinDecl * np.sin(np.radians(lat)) )) \
                / ( cosDecl * np.cos( np.radians(lat) ) )

        if cosHr > 1: # Sun doesnt rise on this loc on this date
            return -1, -1
        elif cosHr < -1: # Sun doesnt set on this location on this date
            return -1, -1
        elif stage == SunCycles.RISING: # Sunrise
            hr = 360 - np.degrees(np.arccos(cosHr))
        elif stage == SunCycles.SETTING:  # Sunset
            hr = np.degrees(np.arccos(cosHr))

        hr = hr / 15. # Convert angle to hours

        localTime = hr + right_ascension - ( 0.06571 * apx ) - 6.622# local meantime of rise/set

        UTtime = localTime - longhr # adjust to UTC

        if UTtime < 0:
            UTtime = UTtime + 24
        elif UTtime > 24:
            UTtime = UTtime - 24

        hour = np.floor(UTtime)

        minute = (UTtime - hour) * 60
        if minute == 60:
            hour = hour + 1
            minute = 0

        return hour, minute