# Path: spyce/human.py
# def to_human_time(seconds):
#     """Convert a timespan in seconds into a human-readable format"""
#     return str(datetime.timedelta(seconds=seconds))
# 
# def to_si_prefix(value, unit=''):
#     """Format value with SI-prefix for easier reading"""
#     exponent_group = math.log(abs(value), 10) // 3
#     mantissa = value / 10**(exponent_group*3)
#     prefix = u'afpnµm kMGTPE'[int(exponent_group) + 6].strip()
#     return '%.4g%s%s' % (mantissa, prefix, unit)
# 
# Path: spyce/analysis.py
# def newton_raphson(x_0, f=None, f_prime=None, ratio=None):
#     """Newton-Raphson method
# 
#     Look around `x_0` for a root of `f`, of derivative `f_prime`. For
#     optimization, their ratio (`f` over `f_prime`) can be directly given
#     instead.
#     """
#     # handle arguments
#     if ratio is None:
#         def ratio(x):
#             return f(x) / f_prime(x)
#     else:
#         if f is not None or f_prime is not None:
#             raise TypeError('specify either ratio or (f and f_prime)')
# 
#     # run Newton-Raphson
#     x = x_0
#     previous_x = 0
#     for _ in range(30):  # upper limit on iteration count
#         previous_previous_x, previous_x = previous_x, x
#         x -= ratio(x)
#         if x in (previous_x, previous_previous_x):
#             # best accuracy reached
#             break
#     return x


import sys
import math
import spyce.load
from spyce.human import to_human_time, to_si_prefix
from spyce.analysis import newton_raphson
            % sys.argv[0], file=sys.stderr)
        sys.exit(1)
    primary = spyce.load.from_name(sys.argv[1])

    R = primary.radius
    mu = primary.gravitational_parameter

    def f(a):
        # note: a for semi-major axis
        return 2 * math.asin(R / a) * math.sqrt(a*a*a / mu)

    # f''(a) / f'(a)
    def ratio(a):
        r = R/a
        x = 1 - r*r
        s = math.asin(r)/r * math.sqrt(x)
        return a * (1.5*s - 1) / (.75*s - 2 + 1/x)

    if len(sys.argv) > 2:
        altitude = float(sys.argv[2])
        semi_major_axis = primary.radius + altitude
        altitude = to_si_prefix(altitude, 'm')
        night_time = to_human_time(f(semi_major_axis))
        print('Consider a satellite in a circular orbit around %s' % primary)
        print('Time in the dark at altitude %s: %s' % (altitude, night_time))
        print('This ignores possible eclipses from natural satellites')
        sys.exit(0)

    # find a root of f'
    # i.e. a local extremum of f

# Path: spyce/human.py
# def to_human_time(seconds):
#     """Convert a timespan in seconds into a human-readable format"""
#     return str(datetime.timedelta(seconds=seconds))
# 
# def to_si_prefix(value, unit=''):
#     """Format value with SI-prefix for easier reading"""
#     exponent_group = math.log(abs(value), 10) // 3
#     mantissa = value / 10**(exponent_group*3)
#     prefix = u'afpnµm kMGTPE'[int(exponent_group) + 6].strip()
#     return '%.4g%s%s' % (mantissa, prefix, unit)
# 
# Path: spyce/analysis.py
# def newton_raphson(x_0, f=None, f_prime=None, ratio=None):
#     """Newton-Raphson method
# 
#     Look around `x_0` for a root of `f`, of derivative `f_prime`. For
#     optimization, their ratio (`f` over `f_prime`) can be directly given
#     instead.
#     """
#     # handle arguments
#     if ratio is None:
#         def ratio(x):
#             return f(x) / f_prime(x)
#     else:
#         if f is not None or f_prime is not None:
#             raise TypeError('specify either ratio or (f and f_prime)')
# 
#     # run Newton-Raphson
#     x = x_0
#     previous_x = 0
#     for _ in range(30):  # upper limit on iteration count
#         previous_previous_x, previous_x = previous_x, x
#         x -= ratio(x)
#         if x in (previous_x, previous_previous_x):
#             # best accuracy reached
#             break
#     return x


# Path: night_time.py
import sys
import math
import spyce.load
from spyce.human import to_human_time, to_si_prefix
from spyce.analysis import newton_raphson

            % sys.argv[0], file=sys.stderr)
        sys.exit(1)
    primary = spyce.load.from_name(sys.argv[1])

    R = primary.radius
    mu = primary.gravitational_parameter

    def f(a):
        # note: a for semi-major axis
        return 2 * math.asin(R / a) * math.sqrt(a*a*a / mu)

    # f''(a) / f'(a)
    def ratio(a):
        r = R/a
        x = 1 - r*r
        s = math.asin(r)/r * math.sqrt(x)
        return a * (1.5*s - 1) / (.75*s - 2 + 1/x)

    if len(sys.argv) > 2:
        altitude = float(sys.argv[2])
        semi_major_axis = primary.radius + altitude
        altitude = to_si_prefix(altitude, 'm')
        night_time = to_human_time(f(semi_major_axis))
        print('Consider a satellite in a circular orbit around %s' % primary)
        print('Time in the dark at altitude %s: %s' % (altitude, night_time))
        print('This ignores possible eclipses from natural satellites')
        sys.exit(0)

    # find a root of f'
    # i.e. a local extremum of f

    semi_major_axis = newton_raphson(primary.radius+1e-6, ratio=ratio)