/* Copyright 2002-2017 CS Systèmes d'Information * Licensed to CS Systèmes d'Information (CS) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * CS licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.orekit.propagation.events; import org.hipparchus.exception.LocalizedCoreFormats; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator; import org.hipparchus.util.FastMath; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.orekit.Utils; import org.orekit.errors.OrekitException; import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.orbits.CircularOrbit; import org.orekit.orbits.EquinoctialOrbit; import org.orekit.orbits.KeplerianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.PositionAngle; import org.orekit.propagation.Propagator; import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.analytical.KeplerianPropagator; import org.orekit.propagation.events.handlers.ContinueOnEvent; import org.orekit.propagation.events.handlers.EventHandler; import org.orekit.propagation.events.handlers.StopOnEvent; import org.orekit.propagation.events.handlers.EventHandler.Action; import org.orekit.propagation.numerical.NumericalPropagator; import org.orekit.propagation.sampling.OrekitFixedStepHandler; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScale; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; import org.orekit.utils.PVCoordinates; import org.orekit.utils.PVCoordinatesProvider; public class EventDetectorTest { private double mu; @Test public void testBasicScheduling() throws OrekitException { final TimeScale utc = TimeScalesFactory.getUTC(); final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc); final Orbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), date, mu); Propagator propagator = new KeplerianPropagator(orbit); double stepSize = 60.0; OutOfOrderChecker checker = new OutOfOrderChecker(stepSize); propagator.addEventDetector(new DateDetector(date.shiftedBy(5.25 * stepSize)).withHandler(checker)); propagator.setMasterMode(stepSize, checker); propagator.propagate(date.shiftedBy(10 * stepSize)); Assert.assertTrue(checker.outOfOrderCallDetected()); } private static class OutOfOrderChecker implements EventHandler<DateDetector>, OrekitFixedStepHandler { private AbsoluteDate triggerDate; private boolean outOfOrderCallDetected; private double stepSize; public OutOfOrderChecker(final double stepSize) { triggerDate = null; outOfOrderCallDetected = false; this.stepSize = stepSize; } public Action eventOccurred(SpacecraftState s, DateDetector detector, boolean increasing) { triggerDate = s.getDate(); return Action.CONTINUE; } public void handleStep(SpacecraftState currentState, boolean isLast) { // step handling and event occurrences may be out of order up to one step // with variable steps, and two steps with fixed steps (due to the delay // induced by StepNormalizer) if (triggerDate != null) { double dt = currentState.getDate().durationFrom(triggerDate); if (dt < 0) { outOfOrderCallDetected = true; Assert.assertTrue(FastMath.abs(dt) < (2 * stepSize)); } } } public boolean outOfOrderCallDetected() { return outOfOrderCallDetected; } @Deprecated @Override public void init(SpacecraftState initialState, AbsoluteDate target) { } @Override public void init(SpacecraftState initialState, AbsoluteDate target, double step) { } } @Test public void testIssue108Numerical() throws OrekitException { final TimeScale utc = TimeScalesFactory.getUTC(); final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc); final Orbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), date, mu); final double step = 60.0; final int n = 100; NumericalPropagator propagator = new NumericalPropagator(new ClassicalRungeKuttaIntegrator(step)); propagator.resetInitialState(new SpacecraftState(orbit)); GCallsCounter counter = new GCallsCounter(100000.0, 1.0e-6, 20, new StopOnEvent<GCallsCounter>()); propagator.addEventDetector(counter); propagator.propagate(date.shiftedBy(n * step)); Assert.assertEquals(n + 1, counter.getCount()); } @Test public void testIssue108Analytical() throws OrekitException { final TimeScale utc = TimeScalesFactory.getUTC(); final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc); final Orbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), date, mu); final double step = 60.0; final int n = 100; KeplerianPropagator propagator = new KeplerianPropagator(orbit); GCallsCounter counter = new GCallsCounter(100000.0, 1.0e-6, 20, new StopOnEvent<GCallsCounter>()); propagator.addEventDetector(counter); propagator.setMasterMode(step, new OrekitFixedStepHandler() { public void handleStep(SpacecraftState currentState, boolean isLast) { } }); propagator.propagate(date.shiftedBy(n * step)); Assert.assertEquals(n + 1, counter.getCount()); } private static class GCallsCounter extends AbstractDetector<GCallsCounter> { private static final long serialVersionUID = 1L; private int count; public GCallsCounter(final double maxCheck, final double threshold, final int maxIter, final EventHandler<? super GCallsCounter> handler) { super(maxCheck, threshold, maxIter, handler); count = 0; } protected GCallsCounter create(final double newMaxCheck, final double newThreshold, final int newMaxIter, final EventHandler<? super GCallsCounter> newHandler) { return new GCallsCounter(newMaxCheck, newThreshold, newMaxIter, newHandler); } public int getCount() { return count; } public double g(SpacecraftState s) { count++; return 1.0; } } @Test public void testNoisyGFunction() throws OrekitException { // initial conditions Frame eme2000 = FramesFactory.getEME2000(); TimeScale utc = TimeScalesFactory.getUTC(); AbsoluteDate initialDate = new AbsoluteDate(2011, 5, 11, utc); AbsoluteDate startDate = new AbsoluteDate(2032, 10, 17, utc); AbsoluteDate interruptDate = new AbsoluteDate(2032, 10, 18, utc); AbsoluteDate targetDate = new AbsoluteDate(2211, 5, 11, utc); KeplerianPropagator k1 = new KeplerianPropagator(new EquinoctialOrbit(new PVCoordinates(new Vector3D(4008462.4706055815, -3155502.5373837613, -5044275.9880020910), new Vector3D(-5012.9298276860990, 1920.3567095973078, -5172.7403501801580)), eme2000, initialDate, Constants.WGS84_EARTH_MU)); KeplerianPropagator k2 = new KeplerianPropagator(new EquinoctialOrbit(new PVCoordinates(new Vector3D(4008912.4039522274, -3155453.3125615157, -5044297.6484738905), new Vector3D(-5012.5883854112530, 1920.6332221785074, -5172.2177085540500)), eme2000, initialDate, Constants.WGS84_EARTH_MU)); k2.addEventDetector(new CloseApproachDetector(2015.243454166727, 0.0001, 100, new ContinueOnEvent<CloseApproachDetector>(), k1)); k2.addEventDetector(new DateDetector(Constants.JULIAN_DAY, 1.0e-6, interruptDate)); SpacecraftState s = k2.propagate(startDate, targetDate); Assert.assertEquals(0.0, interruptDate.durationFrom(s.getDate()), 1.1e-6); } private static class CloseApproachDetector extends AbstractDetector<CloseApproachDetector> { private static final long serialVersionUID = 1L; private final PVCoordinatesProvider provider; public CloseApproachDetector(double maxCheck, double threshold, final int maxIter, final EventHandler<? super CloseApproachDetector> handler, PVCoordinatesProvider provider) { super(maxCheck, threshold, maxIter, handler); this.provider = provider; } public double g(final SpacecraftState s) throws OrekitException { PVCoordinates pv1 = provider.getPVCoordinates(s.getDate(), s.getFrame()); PVCoordinates pv2 = s.getPVCoordinates(); Vector3D deltaP = pv1.getPosition().subtract(pv2.getPosition()); Vector3D deltaV = pv1.getVelocity().subtract(pv2.getVelocity()); double radialVelocity = Vector3D.dotProduct(deltaP.normalize(), deltaV); return radialVelocity; } protected CloseApproachDetector create(final double newMaxCheck, final double newThreshold, final int newMaxIter, final EventHandler<? super CloseApproachDetector> newHandler) { return new CloseApproachDetector(newMaxCheck, newThreshold, newMaxIter, newHandler, provider); } } @Test public void testWrappedException() throws OrekitException { final Throwable dummyCause = new RuntimeException(); try { // initial conditions Frame eme2000 = FramesFactory.getEME2000(); TimeScale utc = TimeScalesFactory.getUTC(); final AbsoluteDate initialDate = new AbsoluteDate(2011, 5, 11, utc); final AbsoluteDate exceptionDate = initialDate.shiftedBy(3600.0); KeplerianPropagator k = new KeplerianPropagator(new EquinoctialOrbit(new PVCoordinates(new Vector3D(4008462.4706055815, -3155502.5373837613, -5044275.9880020910), new Vector3D(-5012.9298276860990, 1920.3567095973078, -5172.7403501801580)), eme2000, initialDate, Constants.WGS84_EARTH_MU)); k.addEventDetector(new DateDetector(initialDate.shiftedBy(Constants.JULIAN_DAY)) { private static final long serialVersionUID = 1L; @Override public double g(final SpacecraftState s) throws OrekitException { final double dt = s.getDate().durationFrom(exceptionDate); if (FastMath.abs(dt) < 1.0) { throw new OrekitException(dummyCause, LocalizedCoreFormats.SIMPLE_MESSAGE, "dummy"); } return dt; } }); k.propagate(initialDate.shiftedBy(Constants.JULIAN_YEAR)); Assert.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assert.assertSame(dummyCause, oe.getCause()); } } @Test public void testDefaultMethods() throws OrekitException { EventDetector dummyDetector = new EventDetector() { private static final long serialVersionUID = 1L; @Override public double getThreshold() { return 1.0e-10; } @Override public int getMaxIterationCount() { return 100; } @Override public double getMaxCheckInterval() { return 60; } @Override public double g(SpacecraftState s) { return s.getDate().durationFrom(AbsoluteDate.J2000_EPOCH); } @Override public Action eventOccurred(SpacecraftState s, boolean increasing) { return Action.RESET_STATE; } }; // by default, this method does nothing, so this should pass without exception dummyDetector.init(null, null); // by default, this method returns its argument SpacecraftState s = new SpacecraftState(new KeplerianOrbit(7e6, 0.01, 0.3, 0, 0, 0, PositionAngle.TRUE, FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH, Constants.EIGEN5C_EARTH_MU)); Assert.assertSame(s, dummyDetector.resetState(s)); } @Before public void setUp() { Utils.setDataRoot("regular-data"); mu = Constants.EIGEN5C_EARTH_MU; } }