Esempio n. 1
0
def planetsplot(userdates=None, delta="1d", master_scale=15, demo=False,
                showplots=False):
    """
    ... explain what this does...
    """

    outdir = './sample_data/output'
    # if demo:
    #     shutil.rmtree(outdir)
    #     os.makedirs(outdir)
    # else:
    #     if not os.path.exists(outdir):
    #         os.makedirs(outdir)
    #     else:
    #         print('\n   Uh-oh! The directory {} already exists.'.format(
    #             outdir))
    #         if yesno('   Do you want to replace it?'):
    #             shutil.rmtree(outdir)
    #             os.makedirs(outdir)
    #         else:
    #             return

    orbitdata = _gatherorbitdata(delta=delta, scale=master_scale)
    ets, dates, orbits, argps, argpxys, nus = orbitdata

    if userdates is None:
        userdates = dates

    if showplots:
        plt.subplot(1, 1, 1)
        for xy in orbits:
            plt.plot([x[0] for x in xy], [y[1] for y in xy],
                     'rx', label='SPICE')
        for xy in argpxys:
            plt.plot(xy[0], xy[1], 'go')
        plt.show()

    if len(orbits[0]) == len(dates) == len(ets):

        # This rotation will put the Hermean perihelion on the X-axis.
        rotang = -argps[0]

        # Load the kernels that this program requires.
        spice.kclear()
        this_dir = os.path.dirname(os.path.realpath(__file__))
        spice.furnsh(os.path.join(this_dir, 'epys.mk'))

        output_files = []

        # A graphic will be created for each 'date' in 'userdates':
        for date in userdates:

            # get the position-index of the 'et' in the 'orbitdata' list
            # of 'ets' that is closest to the 'date' in the 'userdates'
            et = spice.str2et(date)
            dx = ets.index(getclosest(ets, et))

            # -- Outer frame -------------------------------------------------

            # Opacity of degree frame and Venus graphic
            frame_op = 0.8

            # Process calendar time strings
            date = '{} {}'.format(spice.et2utc(et, 'ISOC', 0).split('T')[0],
                                  spice.et2utc(et, 'ISOC', 0).split('T')[1])
            edate, etime = date.split()
            eyear = "{}".format(edate.split('-')[0])
            emonth = "{0:02d}".format(int(edate.split('-')[1]))
            eday = "{0:02d}".format(int(edate.split('-')[2]))
            epoch = "{}/{}/{}".format(eday, emonth, eyear)
            ep_name = "{}{}{}_{}".format(eyear, emonth, eday,
                                         etime.replace(':', ''))

            frame = _outerframe(epoch, frmSize=master_scale, frm_op=frame_op)

            # -- First Point of Aires ----------------------------------------

            # merc_loan = 48.331
            # merc_argp = 29.124
            arend = svg.make_marker("fopa_arrowend", "arrow_end",
                                    fill_opacity=0.4)

            x1, y1 = 10, 0
            x2, y2 = master_scale * 1.3, 0

            fpoa = svg.Line(x1, y1, x2, y2, stroke_width=".4pt",
                            stroke_opacity=0.4, arrow_end=arend)

            xp = (x2 * math.cos(math.radians(rotang)) -
                  y2 * math.sin(math.radians(rotang)))
            yp = (x2 * math.sin(math.radians(rotang)) +
                  y2 * math.cos(math.radians(rotang)))

            fpoa_text = svg.Text(xp + 6.5, yp - 1.0, "First Point of Aries",
                                 font_size=3, opacity=0.75)
            fpoa = svg.Fig(svg.Fig(fpoa, trans=svg.rotate(rotang, 0, 0)),
                           fpoa_text)

            # -- Some containers ---------------------------------------------

            orbs = []
            circles = []
            defs = svg.SVG("defs")

            # -- Orbit circles -----------------------------------------------

            # Build the SVG for each orbit.
            for orbit in orbits:

                if orbits.index(orbit) == 1:
                    orbit_op = 0.4
                else:
                    orbit_op = 1.0

                # Mercury's orbit will have perihelion on the X-axis
                circles.append(svg.Fig(svg.Poly(orbit, stroke_width=".25pt",
                                                stroke_opacity=orbit_op),
                                       trans=svg.rotate(rotang, 0, 0)))

            # -- Planet orbs -------------------------------------------------

            points = [orbits[0][dx], orbits[1][dx], orbits[2][dx]]

            # Build the planet orb for each planet for this chart.
            for point in points:

                # Planetary inputs ...
                if points.index(point) == 0:
                    name = "MERCURY"
                    nu = math.degrees(math.atan2(point[1], point[0])) + rotang
                    if nu < 0:
                        nu = nu + 360
                    # print(nu, nu-rotang, rotang)
                    nu = "{0:03d}".format(int(nu))
                if points.index(point) == 1:
                    name = "VENUS"
                if points.index(point) == 2:
                    name = "EARTH"

                # point_r  = [x/AU for x in point]

                orb, grad = _planetdiag(name, point, rotang)

                orbs.append(orb)
                defs.append(grad)

            # -- Build final figure ------------------------------------------

            wa = master_scale * 1.5
            svgout = svg.Fig(fpoa, frame,
                             circles[0], circles[1], circles[2],
                             orbs[0], orbs[1], orbs[2]
                             ).SVG(svg.window(-wa, wa, -wa, wa))

            svgout.prepend(defs)
            out_path = os.path.join(outdir,
                                    "merc_orbit_plot_{}_{}.svg".format(
                                        ep_name, nu))
            svgout.save(out_path)
            output_files.append(out_path)

        spice.kclear()

        return output_files

    else:
        # You'll jump to hear if the epochs for all 3 planets are not equal.
        print("There is an epoch error between the planet time values...")
Esempio n. 2
0
def mpoplot(userdates, master_scale=15, demo=False):
    """
    ... explain what this does...
    """

    outdir = '../sample_data/output'
    # if demo:
    #     shutil.rmtree(outdir)
    #     os.makedirs(outdir)
    # else:
    #     if not os.path.exists(outdir):
    #         os.makedirs(outdir)
    #     else:
    #         print('\n   Uh-oh! The directory {} already exists.'.format(
    #             outdir))
    #         if yesno('   Do you want to replace it?'):
    #             shutil.rmtree(outdir)
    #             os.makedirs(outdir)
    #         else:
    #             return

    # Clear and load the kernels that this program requires.
    spice.kclear()
    spice.furnsh('epys.mk')

    # A graphic will be created for each 'date' in 'dates':
    for date in userdates:

        et = spice.str2et(date)
        datestr = (spice.et2utc(et, 'ISOC', 0))

        # -- Outer frame -------------------------------------------------

        dist_scl = 250.0

        elts = getorbelts(date)
        arg_peri = elts[4]

        # Opacity of degree frame and Venus graphic
        frame_op = 0.5

        # # Process JD time into calendar time strings
        # datestr = spice.et2utc(et, 'ISOC', 0)
        date = '{} {}'.format(datestr.split('T')[0],
                              datestr.split('T')[1])
        edate, etime = date.split()
        eyear = "{}".format(edate.split('-')[0])
        emonth = "{0:02d}".format(int(edate.split('-')[1]))
        eday = "{0:02d}".format(int(edate.split('-')[2]))
        epoch = "{}/{}/{}".format(eday, emonth, eyear)
        ep_name = "{}{}{}".format(eyear, emonth, eday)

        frame = _outerframe(epoch, frmSize=master_scale, frm_op=frame_op,
                            mpoargp=arg_peri)

        # -- Mercury Planet --------------------------------------------------

        # tru_ano = 90
        # look_from = 270

        # x1 = "{}%".format((100*math.sin(math.radians((tru_ano+90)/2.))))
        # x2 = "{}%".format(100-(100*sin(radians((tru_ano+90)/2.))))

        angs = range(0, 360, 1)

        plt.plot(angs, ["{}".format((100 * math.sin(math.radians(x / 2))))
                        for x in angs], 'yo-')
        plt.plot(angs, ["{}".format(100 - (100 *
                        math.sin(math.radians(x / 2)))) for x in angs], 'ro-')
        # plt.show()

        stop1 = "#C8C5E2"
        # stop2 = "#373163"

        defs = svg.SVG("defs",
                       svg.SVG("linearGradient",
                               svg.SVG("stop", stop_color=stop1,
                                       stop_opacity=1, offset="45%"),
                               svg.SVG("stop", stop_color=stop1,
                                       stop_opacity=1, offset="55%"),
                               x1="0%", y1="0%", x2="100%", y2="0%",
                               spreadMethod="pad",
                               id="mercGrad")
                       )

        # defs = svg.SVG('defs',
        #                svg.SVG('radialGradient',
        #                        svg.SVG('stop',
        #                                stop_color=stop1,
        #                                stop_opacity=1,
        #                                offset='38%'),
        #                        svg.SVG('stop',
        #                                stop_color=stop2,
        #                                stop_opacity=1,
        #                                offset='40%'),
        #                        cx='50%', cy='50%',
        #                        fx='230%', fy='50%',
        #                        r='300%',
        #                        spreadMethod='pad',
        #                        id='mercGrad')
        #                )

        merc_rad = 2439.99  # km
        merc_rad_scl = merc_rad / dist_scl
        merc_ball = svg.Ellipse(0, 0, 0, merc_rad_scl, merc_rad_scl,
                                fill="url(#mercGrad)", stroke_width="0.15pt")

        # -- MPO Orbit --

        mpo_orb_ecc = 0.163229
        mpo_orb_sma = 3394.0  # km
        mpo_orb_sma_scl = mpo_orb_sma / dist_scl
        mpo_orb_smi_scl = mpo_orb_sma_scl * math.sqrt(1 - mpo_orb_ecc ** 2)

        # Make things cleaner
        a = mpo_orb_sma_scl
        b = mpo_orb_smi_scl

        mpo_orb = svg.Ellipse(-math.sqrt(a ** 2 - b ** 2), 0, 0, a, b,
                              fill="none", stroke_width="0.25pt")
        # apof = 8
        mpo_orb_apses = svg.Line(-_rellipse(a, b, 180) - 5, 0,
                                 _rellipse(a, b, 0) + 10, 0,
                                 stroke_width="0.15pt",
                                 stroke_dasharray="2, 2")

        dot_angs = range(0, 360, 20)
        dots = [_orbitdot(a, b, x, color="black") for x in dot_angs]
        mpo_orb_dots = svg.Fig()
        for dot in dots:
            mpo_orb_dots.d.append(dot)

        mpo_orb_trans = svg.rotate(arg_peri, 0, 0)
        mpo_orb_plot = svg.Fig(mpo_orb, mpo_orb_apses, mpo_orb_dots,
                               trans=mpo_orb_trans)

        # -- Direction arrow -------------------------------------------------

        dirarend = svg.make_marker("dirarrowend", "arrow_end",
                                   fill_opacity=0.2)
        dirarend.attr["markerWidth"] = 7.5

        x1, y1 = master_scale + 1, 0.4,
        x2, y2 = master_scale + 1, 1

        dirarwstrt = svg.Line(x1, y1, x2, y2, stroke_width=".4pt",
                              stroke_opacity=0.2, arrow_end=dirarend)

        dirarw = svg.Fig(dirarwstrt, trans="x*cos(y), x*sin(y)")

        # -- Apsis view ------------------------------------------------------

        apvx, apvy = master_scale + 3, -master_scale - 3
        apsisviewball = svg.Ellipse(apvx, apvy,
                                    0, merc_rad_scl * 0.25,
                                    merc_rad_scl * 0.25,
                                    fill="url(#mercGrad)",
                                    stroke_width="0.15pt")

        apsisviewlats = svg.Fig()

        for x in range(-9, 10, 3):

            hscl = math.sin(math.radians(x * 10))
            wscl = math.cos(math.radians(x * 10))

            x1 = apvx - (merc_rad_scl * 0.25 * wscl)
            y1 = apvy + (merc_rad_scl * 0.25 * hscl)
            x2 = apvx + (merc_rad_scl * 0.25 * wscl)
            y2 = apvy + (merc_rad_scl * 0.25 * hscl)

            apsisviewlats.d.append(svg.Line(x1, y1, x2, y2,
                                   stroke_width=".2pt",
                                   stroke_opacity=0.4))

        apvarend = svg.make_marker("apvarrowend",
                                   "arrow_end",
                                   fill_opacity=0.6)
        apvarend.attr["markerWidth"] = 3.0
        apvarend.attr["markerHeight"] = 3.0

        x1, y1 = apvx, apvy - 3
        x2, y2 = apvx, apvy + 3
        apsisvieworbit = svg.Line(x1, y1, x2, y2,
                                  stroke_width=".4pt",
                                  stroke_opacity=0.6,
                                  arrow_end=apvarend)

        xd = apvx
        yd = apvy + (merc_rad_scl * 0.25 * math.sin(math.radians(arg_peri)))
        apsisviewdot = svg.Fig(svg.Dots([(xd, yd)],
                                        svg.make_symbol("apsisdot",
                                                        fill="black",
                                                        fill_opacity=0.6
                                                        ),
                                        0.6, 0.6
                                        )
                               )

        apsisview = svg.Fig(apsisviewball,
                            apsisviewlats,
                            apsisvieworbit,
                            apsisviewdot)

        # -- Build final figure ----------------------------------------------

        wa = master_scale * 1.5
        svgout = svg.Fig(frame,
                         merc_ball,
                         mpo_orb_plot,
                         dirarw,
                         apsisview
                         ).SVG(svg.window(-wa, wa, -wa, wa))

        svgout.prepend(defs)

        argp = int(arg_peri)
        svgout.save(os.path.join(outdir,
                                 "mpo_orbit_plot_{}_{}.svg".format(ep_name,
                                                                   argp)
                                 )
                    )
Esempio n. 3
0
def _gatherorbitdata(delta="1d", scale=15, verbose=False):

    # print("Building orbit for planets with SPICE...")

    spice.kclear()

    # Load the kernels that this program requires.
    this_dir = os.path.dirname(os.path.realpath(__file__))
    spice.furnsh(os.path.join(this_dir, 'epys.mk'))

    # convert starting epoch to ET
    et0 = spice.str2et('2024/05/07 00:00')
    rate = 24 * 2  # Every 30 mins
    days = [(et0 + (day * (86400 / rate))) for day in range(366 * rate)]

    # internal variables and constants
    planets = ("MERCURY", "VENUS", "EARTH")
    AU = consts.AU / 1000.  # AU [km]
    argps = []
    argpxys = []
    xyvecs = []
    nuvecs = []

    for planet in planets:

        # print("     > {}".format(planet))

        dates = []
        rvec = []   # vector of centric radii
        xyvec = []  # vector of (x,y) coordinates
        nuvec = []  # vector of nu (True Anomaly) values
        incvec = []  # vector of inclination values

        for et in days:

            if verbose:
                print('ET Seconds Past J2000: {}'.format(et))

            # Compute the apparent state of MERCURY as seen from
            # the SUN in ECLIPJ2000
            starg, ltime = spice.spkezr(planet, et, 'ECLIPJ2000',
                                        'NONE', 'SUN')

            x, y, z, vx, vy, vz = [el / AU * scale for el in starg]
            r = math.sqrt(x ** 2 + y ** 2 + z ** 2)

            if verbose:
                print('\nApparent state of MERCURY as seen from',
                      ' Sun in the J2000:')
                print(' X = {:10.4f} km (LT+S)'.format(x))
                print(' Y = {:10.4f} km (LT+S)'.format(y))
                print(' Z = {:10.4f} km (LT+S)'.format(z))
                print('VX = {:10.4f} km/s (LT+S)'.format(vx))
                print('VY = {:10.4f} km/s (LT+S)'.format(vy))
                print('VZ = {:10.4f} km/s (LT+S)'.format(vz))

            # calculate orbital elements from the starg state vector
            elts = spice.oscelt(starg, et, planetmu('Sun'))

            # define a solver for Kepler's equation
            ks = pyasl.MarkleyKESolver()

            # solve for the Eccentric Anomaly (E) with the
            # Mean Anomaly (M = elts[5]) and the
            # Eccentricity (ecc = elts[1])
            E = ks.getE(elts[5], elts[1])

            # calculate the True Anomaly (nu) from E and ecc (elts[1])
            nuarg1 = math.sqrt(1 - elts[1]) * math.cos(E / 2)
            nuarg2 = math.sqrt(1 + elts[1]) * math.sin(E / 2)

            # atan2 in python needs the arguments as (y,x)
            # rather than (x,y) ...?
            nu = 2 * math.atan2(nuarg2, nuarg1)

            rvec.append(r)  # append r for each day
            xyvec.append((x, y))  # append (x,y) coords for each day
            nuvec.append(nu)  # append True anomaly for each day

            # build date in ISO format
            date = '{} {}'.format(spice.et2utc(et, 'ISOC', 0).split('T')[0],
                                  spice.et2utc(et, 'ISOC', 0).split('T')[1])
            dates.append(date)  # append date for each day
            incvec.append(elts[2])  # append inc. for each day (rads)

            # print(date, nu * spice.dpr(), x, y, z, r, elts[0])

        # for this planet find the argument of pericenter (argp):
        # find the index of the min. r value for calculated range.
        argpi = rvec.index(min(rvec))

        # calculate argp x and y values and argp using atan2
        argpxy = (xyvec[argpi][0], xyvec[argpi][1] * math.cos(incvec[argpi]))
        argp = math.degrees(math.atan2(argpxy[1], argpxy[0]))

        argpxys.append(argpxy)  # append argp (x,y) coords.
        argps.append(argp)  # append argp
        xyvecs.append(xyvec)  # append (x,y) coords. vector
        nuvecs.append(nuvec)  # append true anomaly vector

    spice.kclear()

    return days, dates, xyvecs, argps, argpxys, nuvecs