Help with OEM export/import

I am generating an OEM file following the test code in OrekitEphemerisFileTest

        OrekitEphemerisFile ephemerisFile = new OrekitEphemerisFile();
        OrekitEphemerisFile.OrekitSatelliteEphemeris satelliteEphemeris = ephemerisFile.addSatellite(satId);
        satelliteEphemeris.addNewSegment(states);

        OemMetadata template = new OemMetadata(8);
        template.setTimeSystem(TimeSystem.UTC);
        template.setObjectID(satId);
        template.setObjectName(satId);
        template.setCenter(new BodyFacade("EARTH", CelestialBodyFactory.getCelestialBodies().getEarth()));
        template.setReferenceFrame(FrameFacade.map(FramesFactory.getGCRF()));
        EphemerisWriter writer = new EphemerisWriter(new WriterBuilder().buildOemWriter(),
                null, template, FileFormat.KVN, "dummy", 60);
        writer.write("output.oem", ephemerisFile);

And then importing it using

        OemParser parser = new ParserBuilder().buildOemParser();
        Oem oem = parser.parse(new DataSource(fileName));
        return oem.getSatellites().get(satId).getPropagator();

Which works perfectly! But when I change to generating an XML-formatted OEM by changing the writer instantiation

        EphemerisWriter writer = new EphemerisWriter(new WriterBuilder().buildOemWriter(),
                null, template, FileFormat.XML, "dummy", 60);

then the import fails with

Exception in thread “main” org.orekit.errors.OrekitException: unexpected keyword in CCSDS line number 21 of file output.oem:
stateVector

I’m clearly doing something wrong, but I’m not sure what I should change to generate the XML version of the file?

An example of the result might help!

<?xml version="1.0" encoding="UTF-8"?>
<oem id="CCSDS_OEM_VERS" version="3.0">
  <header>
    <CREATION_DATE>2022-04-15T01:12:47.0</CREATION_DATE>
    <ORIGINATOR>OREKIT</ORIGINATOR>
  </header>

  <body>

    <metadata>
      <OBJECT_NAME>M2B</OBJECT_NAME>
      <OBJECT_ID>M2B</OBJECT_ID>
      <CENTER_NAME>EARTH</CENTER_NAME>
      <REF_FRAME>GCRF</REF_FRAME>
      <TIME_SYSTEM>UTC</TIME_SYSTEM>
      <START_TIME>2022-04-11T06:08:15.99</START_TIME>
      <STOP_TIME>2022-04-15T06:08:15.99</STOP_TIME>
      <INTERPOLATION_DEGREE>1</INTERPOLATION_DEGREE>
    </metadata>

    <stateVector>
      <EPOCH>2022-04-11T06:08:15.99</EPOCH>
      <X units="km">5425.413665789079</X>
      <Y units="km">3536.494944806805</Y>
      <Z units="km">2457.383413345264</Z>
      <X_DOT units="km/s">-1.6668016823846241</X_DOT>
      <Y_DOT units="km/s">5.774130830354613</Y_DOT>
      <Z_DOT units="km/s">-4.631954506533044</Z_DOT>
    </stateVector>
    <stateVector>
    ...
    </stateVector>
  </body>
</oem>

Looking at the example xml oem in the test resources, there might be a set of <data> tags missing from around the stateVector elements?

Yes the tags seems to be missing.
This is strange because there are explicit methods to handle them (see OemWriter line 516).

Could you check in a debugger in your case if these methods are called or not? The expected call sequence is writer.write() →writeSegment() → writeSegmentContent() → startData() and endData()

Hi Mark,

I agree with Luc, that’s very strange because the write(...) method of the EphemerisWriter seems to perform the same steps as the writeMessage(...) method of the OemWriter.

Please find below a workaround that works:


// Format
        final FileFormat format = FileFormat.XML;

        // Header
        final Header header = new Header(3);

        // Metadata
        final OemMetadata template = new OemMetadata(8);
        template.setTimeSystem(TimeSystem.UTC);
        template.setObjectID("M2B");
        template.setObjectName("M2B");
        template.setCenter(new BodyFacade("EARTH", CelestialBodyFactory.getCelestialBodies().getEarth()));
        template.setReferenceFrame(FrameFacade.map(FramesFactory.getGCRF()));
        template.setStartTime(states.get(0).getDate());
        template.setStopTime(states.get(states.size() - 1).getDate());

        // Data
        final OemData data = new OemData();
        // Loops over collected states
        for (SpacecraftState state : states) {
           // Adds the state vector
           data.addData(state.getPVCoordinates(), true);
        }

        // Segment
        final List<OemSegment> segments = new ArrayList<>();
        segments.add(new OemSegment(template, data, states.get(0).getMu()));

        // Oem
        final Oem oem = new Oem(header, segments, IERSConventions.IERS_2010, DataContext.getDefault(), states.get(0).getMu());

        // Write
        final OemWriter oemWriter = new WriterBuilder().buildOemWriter();
        try (BufferedWriter writer =
                        Files.newBufferedWriter(Paths.get("output.oem"), StandardCharsets.UTF_8);
             final Generator generator = format == FileFormat.KVN ?
                                         new KvnGenerator(writer, OemWriter.KVN_PADDING_WIDTH, "output.oem", 0) :
                                         new XmlGenerator(writer, XmlGenerator.DEFAULT_INDENT, "output.oem", false)) {
            oemWriter.writeMessage(generator, oem);
        } catch (IOException e) {
            System.out.println(e.getLocalizedMessage());
        }

        // Read the file
        OemParser parser = new ParserBuilder().buildOemParser();
        Oem oemParsed = parser.parse(new DataSource("output.oem"));

Bryan

I haven’t used a debugger to trace java code before, so it’s very possible I’ve done something wrong …

From writer (which is an EphemerisWriter) the call path is just
writer.write()writer.writeSegment()writer.writeOrbitEphemerisLine()
There isn’t any call to writeSegmentContent()? writeSegment() is in EphemerisWriter and writeOrbitEphemerisLine() is in OemWriter.

You got it right. I’m looking at this.
Could you open an issue in the forge?

No worries! I just created issue 917.

Thanks!
I have pushed a fix.

It works perfectly, thankyou!