def test_dummy(ccsds_format): with raises(TypeError): dumps(None, fmt=ccsds_format) with raises(CcsdsError): loads("dummy text")
def test_dump_opm_man_continuous(orbit_continuous_man, datafile, ccsds_format, helper): ref = datafile("opm_continuous_man_tnw") txt = dumps(orbit_continuous_man, fmt=ccsds_format) helper.assert_string(ref, txt) ref = datafile("opm_continuous_man_qsw") for man in orbit_continuous_man.maneuvers: man.frame = "QSW" man._dv = np.array([man._dv[1], man._dv[0], man._dv[2]]) txt = dumps(orbit_continuous_man, fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_opm_interplanetary(jplfiles, orbit, ccsds_format, datafile, helper): create_frames("Mars") orbit.frame = "Mars" txt = dumps(orbit, fmt=ccsds_format) helper.assert_string(datafile("opm_interplanetary"), txt)
def test_dump_oem_linear(ephem, ccsds_format): ephem.method = ephem.LINEAR txt = dumps(ephem, fmt=ccsds_format).splitlines() for line in txt: if "INTERPOLATION" in line: assert "LINEAR" in line
def test_dump_omm_cov(orbit_cov, datafile, ccsds_format, helper): tle_cov = orbit_cov.copy(form="TLE") ref = datafile("omm_cov") txt = dumps(tle_cov, fmt=ccsds_format) helper.assert_string(ref, txt) tle_cov2 = tle_cov.copy() tle_cov2.cov.frame = "TNW" txt = dumps(tle_cov2, fmt=ccsds_format) helper.assert_string(datafile("omm_cov_tnw"), txt) tle_cov3 = tle_cov.copy() tle_cov3.cov.frame = "QSW" txt = dumps(tle_cov3, fmt=ccsds_format) helper.assert_string(datafile("omm_cov_qsw"), txt)
def test_dump_opm(orbit, datafile, ccsds_format, helper, kep): kep = kep == "kep" ref = datafile("opm", kep) txt = dumps(orbit, fmt=ccsds_format, kep=kep) helper.assert_string(ref, txt)
def test_dump_omm_user_defined(tle, ccsds_format, datafile, helper): subdict = tle._data["ccsds_user_defined"] = {} subdict["FOO"] = "foo enters" subdict["BAR"] = "a bar" txt = dumps(tle, fmt=ccsds_format) helper.assert_string(datafile("omm_user_defined"), txt)
def test_dump_oem_interplanetary(jplfiles, ephem, ccsds_format, datafile, helper): ephem.frame = "MarsBarycenter" ref = datafile("oem_interplanetary") txt = dumps(ephem, fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_opm_user_defined(orbit, ccsds_format, datafile, helper): subdict = orbit.complements["ccsds_user_defined"] = {} subdict["FOO"] = "foo enters" subdict["BAR"] = "a bar" txt = dumps(orbit, fmt=ccsds_format) helper.assert_string(datafile("opm_user_defined"), txt)
def test_tle(tle, ccsds_format): # Check that a TLE and its OMM representation are the same txt = dumps(tle, fmt=ccsds_format) orb = loads(txt) new_tle = Tle.from_orbit(orb) assert str(tle.tle) == str(new_tle) assert all(tle == orb) date = Date(2020, 9, 30) assert all(tle.propagate(date) == orb.propagate(date))
def test_dump_opm_cov(orbit_cov, datafile, ccsds_format, helper): ref = datafile("opm_cov") txt = dumps(orbit_cov, fmt=ccsds_format) helper.assert_string(ref, txt) # Conversion to TNW orbit_cov2 = orbit_cov.copy() orbit_cov2.cov.frame = "TNW" txt = dumps(orbit_cov2, fmt=ccsds_format) helper.assert_string(datafile("opm_cov_tnw"), txt) # Conversion to QSW orbit_cov3 = orbit_cov.copy() orbit_cov3.cov.frame = "QSW" txt = dumps(orbit_cov3, fmt=ccsds_format) helper.assert_string(datafile("opm_cov_qsw"), txt)
def dumps(data, **kwargs): """Convert an Orbit or Ephem instance into a string formatted along the CCSDS standard This function is a wrapper of :py:func:`beyond.io.ccsds.dumps` and allows to integrate some space-command specific fields """ if isinstance(data, Orbit): subdict = data.complements.setdefault("ccsds_user_defined", {}) subdict["PROPAGATOR"] = data.propagator.__class__.__name__ if data.propagator.__class__.__name__ == "KeplerNum": subdict["PROPAGATOR_STEP_SECONDS"] = "{:0.3f}".format( data.propagator.step.total_seconds()) subdict["PROPAGATOR_METHOD"] = data.propagator.method return ccsds.dumps(data, **kwargs)
def test_dump_omm_bluebook(ccsds_format, datafile, str_tle_bluebook): """Example from the CCSDS Blue Book (4-1 and 4-2) """ tle = Tle(str_tle_bluebook) omm = tle.orbit() # omm.name = tle.name # omm.norad_id = tle.norad_id # omm.cospar_id = tle.cospar_id # assert tle.epoch == Date(2007, 5, 4, 10, 34, 41, 426400) omm = dumps(omm, fmt=ccsds_format).splitlines() ref_bluebook = datafile("omm_bluebook").splitlines() assert ref_bluebook[0] == omm[0] for i in range(4, len(ref_bluebook)): assert ref_bluebook[i] == omm[i]
def space_ephem(*argv): # pragma: no cover """Compute ephemeris from a given TLE Usage: space-ephem get <selector>... space-ephem insert (- | <file>) space-ephem compute (- | <selector>...) [options] space-ephem list <selector>... [options] Option get Retrieve an existing ephemeris from the database list List existing ephemerides compute Compute ephemeris from a TLE insert Insert a ephemeris into the database <selector> Selector of the satellite -f, --frame <frame> Frame in which to write the file to -d, --date <date> Start date of the ephem [default: midnight] (format %Y-%m-%dT%H:%M:%S) -r, --range <days> Duration of extrapolation [default: 3d] -s, --step <step> Step size of the ephemeris [default: 180s] -i, --interp <inter> Interpolation method (linear, lagrange) [default: lagrange] --insert Insert the computed ephemeris into the database --force Force insertion -l, --last <last> When listing print the last N ephems [default: 10] """ from .utils import docopt from .sat import Sat args = docopt(space_ephem.__doc__, argv=argv) if args["compute"]: try: start = parse_date(args["--date"]) stop = parse_timedelta(args["--range"]) step = parse_timedelta(args["--step"]) satlist = Sat.from_input( *args["<selector>"], text=sys.stdin.read() if args["-"] else "") except ValueError as e: log.error(e) sys.exit(1) ephems = [] for sat in satlist: ephem = sat.orb.ephem(start=start, stop=stop, step=step) ephem.name = sat.name ephem.cospar_id = sat.cospar_id ephem.method = args["--interp"] if args["--frame"] is not None: ephem.frame = StationDb.get(args["--frame"]) ephems.append(ephem) txt = ccsds.dumps(ephems, originator=config.get("center", "name", fallback="N/A")) print(txt) print("") if args["insert"] or (args["compute"] and args["--insert"]): if args["--insert"]: pass elif args["-"] and not sys.stdin.isatty(): txt = sys.stdin.read() else: txt = open(args["<file>"]).read() try: sats = Sat.from_input(text=txt, create=True) except ValueError as e: log.error(e) sys.exit(1) for sat in sats: db = EphemDb(sat) try: db.insert(sat.orb, args["--force"]) except FileExistsError as e: continue elif args["list"]: max_idx = int(args["--last"]) try: for sat in Sat.from_selector(*args["<selector>"], type="oem"): print(sat.name) print("idx Start Stop Steps") print("-" * 55) print(sat.req) for idx, ephem in enumerate(EphemDb(sat).list()): if (sat.req.limit == "any" and idx == sat.req.offset or ephem.start == sat.orb.start): color = "* \033[32m" endcolor = "\033[39m" else: color = " " endcolor = "" if idx >= max_idx: break steps = set() for orb_i, orb_j in zip(ephem[:-1], ephem[1:]): steps.add(orb_j.date - orb_i.date) if len(steps) == 1: steps, = steps else: steps = "[{}, {}]".format(min(steps), max(steps)) print( "{color}{idx:<2} {ephem.start:{fmt}} {ephem.stop:{fmt}} {steps}{endcolor}" .format( idx=idx, ephem=ephem, fmt="%Y-%m-%dT%H:%M:%S", steps=steps, color=color, endcolor=endcolor, )) print() except ValueError as e: log.error(e) sys.exit(1) elif args["get"]: ephems = [] try: for sat in Sat.from_selector(*args["<selector>"], src="oem"): if not isinstance(sat.req.date, Date): ephem = EphemDb(sat).get(offset=sat.req.offset) else: ephem = EphemDb(sat).get_dated(date=sat.req.date, limit=sat.req.limit) ephems.append(ephem) except ValueError as e: log.error(e) sys.exit(1) print(ccsds.dumps(ephems))
def test_dump_omm(tle, datafile, ccsds_format, helper): ref = datafile("omm") txt = dumps(tle, fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_oem_cov_tnw(ephem_cov, ccsds_format, datafile, helper): ephem_cov[0].cov.frame = "TNW" txt = dumps(ephem_cov, fmt=ccsds_format) helper.assert_string(datafile("oem_cov_tnw"), txt)
def test_dump_oem_cov(ephem_cov, ccsds_format, datafile, helper): txt = dumps(ephem_cov, fmt=ccsds_format) helper.assert_string(datafile("oem_cov"), txt)
def space_sat(*argv): """Get sat infos Usage: space-sat alias <alias> <selector> [--force] space-sat list-aliases space-sat orb <selector> space-sat sync space-sat infos <selector> Options: alias Create an alias for quick access orb Display the orbit corresponding to the selector list-aliases List existing aliases sync Update satellite database with existing TLEs infos Display informations about a satellite <selector> See below Satellite selectors ISS : latest TLE of ISS norad=25544 : latest TLE of ISS selected by norad number cospar=2018-027A : latest TLE of GSAT-6A ISS@oem : latest OEM ISS@tle : latest TLE ISS~ : before last TLE ISS~~ : 2nd before last TLE ISS@oem~25 : 25th before last OEM ISS@oem^2018-12-25 : first OEM after the date ISS@tle?2018-12-25 : first tle before the date """ # TODO # ISS@opm : latest OPM from .utils import docopt from .tle import space_tle from .ephem import space_ephem args = docopt(space_sat.__doc__, argv=argv) if args["alias"]: selector = args["<selector>"] name = args["<alias>"] try: sat = Sat.from_input(selector) except ValueError as e: log.error("Unknown satellite '{}'".format(selector)) sys.exit(1) q = Alias.select().where(Alias.name == name) if q.exists(): if args["--force"]: alias = q.get() alias.selector = selector alias.save() log.info("Alias '{}' ({}) created".format(name, selector)) else: log.error("Alias '{}' already exists for '{}'".format( name, q.get().selector)) sys.exit() else: Alias(selector=selector, name=name).save() log.info("Alias '{}' ({}) created".format(name, selector)) elif args["list-aliases"]: for alias in Alias: print("{:20} {}".format(alias.name, alias.selector)) elif args["sync"]: sync() elif args["orb"]: try: sat = list(Sat.from_selector(args["<selector>"]))[0] except ValueError as e: log.error(e) sys.exit(1) if isinstance(sat.orb, Ephem): print(ccsds.dumps(sat.orb)) else: print("{0.name}\n{0}".format(sat.orb.tle)) elif args["infos"]: try: sat, = Sat.from_input(args["<selector>"], orb=False) print("""name {0.name} cospar id {0.cospar_id} norad id {0.norad_id} folder {0.folder} """.format(sat)) except ValueError as e: log.error(e) sys.exit(1)
def test_dump_opm_man_impulsive(orbit_man, datafile, ccsds_format, helper): ref = datafile("opm_impulsive_man") txt = dumps(orbit_man, fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_oem(ephem, datafile, ccsds_format, helper): ref = datafile("oem") txt = dumps(ephem, fmt=ccsds_format) helper.assert_string(ref, txt)
def space_planet(*args): """Compute position of a planet of the solar system and its major moons Usage: space-planet space-planet fetch space-planet <planet>... [options] Options: fetch Retrieve .bsp file <planet> Names of the planet to compute the ephemeris of. If absent, list all bodies available -f, --frame <frame> Frame in which to display the ephemeris to [default: EME2000] -d, --date <date> Start date of the ephem (%Y-%m-%d) [default: midnight] -r, --range <days> Duration of extrapolation [default: 3d] -s, --step <step> Step size of the ephemeris. [default: 60m] -a, --analytical Force analytical model instead of .bsp files Example: space-planet Mars # Position of Mars in EME2000 space-planet Moon -f Phobos # Position of the moon as seen from Phobos This command relies on .bsp files, parsed by the incredible jplephem lib. Bsp file can be retrieved at https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/ Files examples: de432s.bsp Moon, Sun, Mercury, Venus and main bodies barycentre mar097.bsp Mars, Phobos and Deimos jup310.bsp Jupiter and its major moons sat360xl.bsp Saturn and its major moons The 'beyond.env.jpl' config variable must be set to a list of bsp files paths. See beyond documentation about JPL files: http://beyond.readthedocs.io/en/latest/api/env.html#module-beyond.env.jpl If no .bsp file is provided, the command falls back to analytical methods for Moon and Sun. Other bodies are not provided. """ import requests from logging import getLogger log = getLogger(__name__) args = docopt(space_planet.__doc__) if args["fetch"]: folder = ws.folder / "jpl" if not folder.exists(): folder.mkdir() naif = "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/" baseurl = { "de403_2000-2020.bsp": naif + "spk/planets/a_old_versions/", # Data until 2020-01-01 "de430.bsp": naif + "spk/planets/", "de432s.bsp": naif + "spk/planets/", "de435.bsp": naif + "spk/planets/", "jup310.bsp": naif + "spk/satellites/", "sat360xl.bsp": naif + "spk/satellites/", "mar097.bsp": naif + "spk/satellites/", "pck00010.tpc": naif + "pck/", "gm_de431.tpc": naif + "pck/", } success = [] filelist = ws.config.get("beyond", "env", "jpl", fallback="de403_2000-2020.bsp") if not isinstance(filelist, list): filelist = [filelist] for filepath in filelist: filepath = Path(filepath) if not filepath.is_absolute(): filepath = folder / filepath if not filepath.exists(): url = baseurl.get(filepath.name, "") + str(filepath.name) log.info("Fetching {}".format(filepath.name)) log.debug(url) try: r = requests.get(url, stream=True) except requests.exceptions.ConnectionError as e: log.error(e) else: try: r.raise_for_status() except requests.exceptions.HTTPError as e: log.error("{} {}".format(filepath.name, e)) else: total = int(r.headers.get("content-length", 0)) size = 0 with filepath.open("bw") as fp: for chunk in r.iter_content(chunk_size=1024): fp.write(chunk) if total: size += len(chunk) print( "\r> {:6.2f} % {} / {}".format( 100 * size / total, humanize(size), humanize(total), ), end="", ) if total: print("\r", " " * 40, end="\r") success.append(str(filepath.absolute())) log.debug("Adding {} to the list of jpl files".format( filepath.name)) else: success.append(str(filepath.absolute())) log.info("File {} already downloaded".format(filepath.name)) # Adding the file to the list and saving the new state of configuration if success: ws.config.set("beyond", "env", "jpl", success) ws.config.save() elif args["<planet>"]: try: date = parse_date(args["--date"], fmt="date") stop = parse_timedelta(args["--range"]) step = parse_timedelta(args["--step"]) except ValueError as e: print(e, file=sys.stderr) sys.exit(1) if not args["--analytical"]: # Create all frames from .bsp files, if they are available try: jpl.create_frames() except jpl.JplError: jpl_error = True else: jpl_error = False # Create all frames from stations database StationDb.list() try: frame = get_frame(args["--frame"]) except UnknownFrameError as e: print(e, file=sys.stderr) sys.exit(1) # Computation ephems = [] for body_name in args["<planet>"]: try: if args["--analytical"] or jpl_error: body = solar.get_body(body_name).propagate(date) else: body = jpl.get_orbit(body_name, date) except UnknownBodyError as e: print(e, file=sys.stderr) sys.exit(1) ephem = body.ephem(start=date, stop=stop, step=step) ephem.frame = frame ephem.name = body_name ephems.append(ephem) else: print(ccsds.dumps(ephems)) else: print("List of all available bodies") try: jpl.create_frames() txt = recurse(jpl.get_frame("Earth").center.node, set()) except jpl.JplError as e: print(" Sun") print(" Moon") else: print(txt)
def test_dump(measureset, station, ccsds_format, datafile, helper): ref = datafile("tdm") txt = dumps(measureset, fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_opm(orbit, datafile, ccsds_format, helper): ref = datafile("opm") txt = dumps(orbit, fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_double_oem(ephem, ephem2, datafile, ccsds_format, helper): ref = datafile("oem_double") txt = dumps([ephem, ephem2], fmt=ccsds_format) helper.assert_string(ref, txt)
def test_dump_opm_man_continuous(orbit_continuous_man, datafile, ccsds_format, helper): ref = datafile("opm_impulsive_man") txt = dumps(orbit_continuous_man, fmt=ccsds_format) helper.assert_string(ref, txt, ignore="MAN_DURATION")