Hi everyone,
I am using Orekit for orbit determination purposes and it seems I have some troubles using the measurements. I had the following exception:
java.lang.RuntimeException: java.lang.IllegalArgumentException: Comparison method violates its general contract!
...
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:777)
at java.util.TimSort.mergeAt(TimSort.java:514)
at java.util.TimSort.mergeCollapse(TimSort.java:439)
at java.util.TimSort.sort(TimSort.java:245)
at java.util.Arrays.sort(Arrays.java:1512)
at org.orekit.estimation.leastsquares.BatchLSEstimator$Provider.getEstimatedMeasurement(BatchLSEstimator.java:645)
After some researches it seems this error shows when the transitivity of the method compareTo in ComparableMeasurements is not respected.
I think I understand why I had some trouble in my case.
I think the problem comes particularly form these lines (59-62) in ComparableMeasurement:
if (thisV.length > otherV.length) {
result = +1;
} else if (thisV.length < otherV.length) {
result = 1;
}
Therefore if I use AngularAzEl azEl measurement and Range range measurements at the same dates, azel.comareTo(range) = 1 and range.compareTo(azel) = 1, which violates the transitivity rule.
You can find this result by running the following test (after Orekit data initialization):
import org.hipparchus.util.FastMath;
import org.junit.jupiter.api.Test;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.estimation.measurements.AngularAzEl;
import org.orekit.estimation.measurements.GroundStation;
import org.orekit.estimation.measurements.ObservableSatellite;
import org.orekit.estimation.measurements.Range;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.TopocentricFrame;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
public class EstimatedMeasurementsOrderTest {
@Test
public void testDifferentSize() {
OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING,
FramesFactory.getITRF(IERSConventions.IERS_2010, false));
TopocentricFrame stationFrame = new TopocentricFrame(earth, new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(0.0), 0.0), "station");
GroundStation station = new GroundStation(stationFrame);
AbsoluteDate date = AbsoluteDate.FIFTIES_EPOCH;
ObservableSatellite satellite = new ObservableSatellite(0);
Range range = new Range(station, false, date, 400e3, 1.0, 1.0, satellite);
AngularAzEl azel = new AngularAzEl(station, date, new double[] {1.0, 0.5}, new double[] {1.0e-2, 1.0e-2}, new double[] {1.0, 1.0}, satellite);
System.out.println(range.compareTo(azel));
System.out.println(azel.compareTo(range));
}
}
I think a simple solution would be just to return -1 when the length is lower (in line 62). What do you think?
Thank you for your time,
Dorian