How to handle OEM files outside of Orekit package ccsds?

Dear all,

I’m facing some issues with the CCSDS OEM implementation.

  1. The first one is creating an OEMFile from scratch:
    In my own application outside of Orekit I would like to create an OEMFile from a propagation result.
    I’d like to set the header, metadata and ephemeris lines by hand and sequentially.
    But I’m facing an issue since most setters in ccsds package seems to be package private.
    Is there something I missed?
    Maybe I should implement my own EphemerisFile or use the OrekitEphemerisFile instead?

  2. I think I found some limitations in StreamingOemWriter class:

  • The first one is that only one header comment can be added.
    This one is hard to fix since the class takes a Map<Keyword, String> as input and thus only one Keyword.COMMENT can be added.
    Maybe we should add an argument with List<String> headerComment or an attribute and setter if we don’t want to change the API.

  • The second one is that I would like to format the output a little more, especially setting the number of decimal digits in the ephemeris data lines.
    But method StreamingOemWriter#Segment.writeEphemerisLine is doing Double.toString(value) to print the values.
    Maybe it would be nice to have some settable format for position and velocity or DecimalFormat(s) so some systems’ specific OEM files requirements can be met.

  • I found out that if I’m trying to write a long OEM file it stops writing after about 38860 lines.
    I think it’s a limitation in size of the OutputStreamWriter I was using as input of StreamingOemWriter but I couldn’t find any info on this on the web.
    I did my own implementation and replaced the Appendable writer with an OutputStream and the problem diseappeared. i don’t know what we could do about this though.
    I’d like to provide a test but I can’t produce my own OEM as stated in 1. I found the issue after parsing/re-writing an existing file that is quite huge and proprietary so I cannot send it along with a test.


Indeed, as most of setters are package private, the only way to create an OEMFile is to create it during a propagation and not after a propagation. First solution is to set the setters as public methods. The second solution is to implement your own EphemerisFile with public setters.
I would prefer the first solution because it can be very useful to create OEM file from scratch.
The change can be performed for a minor version. However, I dont’ know if it is a dangerous thing to let setters be public methods (I think no).
First issue to open :wink:

You can open another issue for that class.

Unfortunately, multimap are not yet available in Java :slightly_smiling_face:
I agree with your proposal of adding an argument List<String> headerComment with a public setter. To my mind, it is the best solution to be compatible with a minor version.

+1. We can add a new method signature for StreamingOemWriter.newSegment(...). To not change the API, we can have a default implementation with a default format.

1 Like

The first bullet point is possible now. Just use metadata.put(COMMENT, "first line of my comment\nCOMMENT second line of my comment"). Perhaps there is a new feature there to make it more intuitive or to update the docs.

Second bullet point would be a nice new feature.

The third one is an odd bug. Do you have a back trace from where it is stalled? Do you now how many bytes that is?

Hi @bcazabonne and @evan.ward,

Thank you both for your quick answers.

Thanks for this Evan.
I’m not sure it is very intuitive indeed. Maybe adding a list of header comments would be more.

I’ll add it as a feature issue on the forge.

I don’t know neither if it’s an issue to make these objects mutable. @evan.ward any idea?
I know you too have developed some of the classes in package CCSDS. However I don’t know the original author “sports” , maybe he would have an interesting opinion on that matter.
We could add some builder classes for CCSDS files but it may be overkill for this and the ccsds package is already quite large and hard to navigate in imho.

I made a test (3.5 KB). It seems more complicated than what I first thought.

  • If I propagate 1 hour, the 2 last lines of my file are:
2000-02-01T00:57:00.0 -4879.925590148858 -1231.5160511791437 13684.803745750496 -0.9878054013566332 -5.206485486794826 -0.13235593330500425

So last line is cut after three characters and we’re missing 3 minutes of data.

  • 30 days:
2000-03-01T23:08:00.0 1362.4821353642772 -12152.33404878204 -11137.388098576641 1.6237164237615005 3.2725707418548553 -2.877211898206439
2000-03-01T23:09:00.0 1459.683670918406 -11

Missing 51 minutes and last line is cut.

  • 29 days:
2000-02-29T23:04:00.0 4929.449929144503 9114.03077650678 -9215.752008187204 -0.665172241833692 3.6775631219226965 4.116863519798882
2000-02-29T23:05:00.0 4888.213719023973 9332.206657719027 -8966.276950813 -0.7093589962889102 3.594539808739104 4.198695179

Missing 54 minutes but last line is full.

I am confused. Am I doing something wrong? Do you get the same results as I do?


Don’t forget to flush. :wink: You’ve closed the OutputStream before the Writer was closed, so any data that was in the buffer waiting to be written was lost. I like to declare all Streams/Writers in a try-with-resources block so they are closed in the correct order.

I think the package was originally designed to just read OEM files so there was no need for changing data. Is read only useful after the file has been parsed? Maybe it makes it easier to pass the file around to different parts of the code without worrying about unexpected modifications. It also seems useful to be able to edit the file and then write it back out again.

Aaah… Can’t believe it was just this. :cry:
I should have guessed it.
Thanks a lot Evan !!

Indeed but it’s not like an orbit or a detector that be will used at runtime. The OEM is merely a container for a formatted ephemeris. It’s easy to navigate in it and detect if some unexpected modifications were performed on it.

I do tend to think this way.