Java tutorial
/* Copyright 2002-2015 CS Systmes d'Information * Licensed to CS Systmes 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.attitudes; import java.util.ArrayList; import java.util.List; import org.apache.commons.math3.geometry.euclidean.threed.Rotation; import org.apache.commons.math3.geometry.euclidean.threed.RotationOrder; import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; import org.apache.commons.math3.util.FastMath; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.orekit.Utils; import org.orekit.bodies.CelestialBodyFactory; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.errors.PropagationException; import org.orekit.frames.FramesFactory; import org.orekit.frames.LOFType; import org.orekit.orbits.KeplerianOrbit; import org.orekit.orbits.Orbit; import org.orekit.propagation.Propagator; import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.analytical.EcksteinHechlerPropagator; import org.orekit.propagation.events.DateDetector; import org.orekit.propagation.events.EclipseDetector; import org.orekit.propagation.events.EventDetector; import org.orekit.propagation.events.EventsLogger; import org.orekit.propagation.events.handlers.ContinueOnEvent; import org.orekit.propagation.events.handlers.EventHandler; import org.orekit.propagation.sampling.OrekitFixedStepHandler; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.AngularDerivativesFilter; import org.orekit.utils.Constants; import org.orekit.utils.PVCoordinates; import org.orekit.utils.PVCoordinatesProvider; public class AttitudesSequenceTest { private AbsoluteDate lastChange; private boolean inEclipse; @Test public void testDayNightSwitch() throws OrekitException { // Initial state definition : date, orbit final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), initialDate, Constants.EIGEN5C_EARTH_MU); final // Attitudes sequence definition EventsLogger logger = new EventsLogger(); final AttitudesSequence attitudesSequence = new AttitudesSequence(); final AttitudeProvider dayObservationLaw = new LofOffset(initialOrbit.getFrame(), LOFType.VVLH, RotationOrder.XYZ, FastMath.toRadians(20), FastMath.toRadians(40), 0); final AttitudeProvider nightRestingLaw = new LofOffset(initialOrbit.getFrame(), LOFType.VVLH); final PVCoordinatesProvider sun = CelestialBodyFactory.getSun(); final PVCoordinatesProvider earth = CelestialBodyFactory.getEarth(); final EclipseDetector ed = new EclipseDetector(sun, 696000000., earth, Constants.WGS84_EARTH_EQUATORIAL_RADIUS).withHandler(new ContinueOnEvent<EclipseDetector>() { public EventHandler.Action eventOccurred(final SpacecraftState s, final EclipseDetector d, final boolean increasing) { setInEclipse(s.getDate(), !increasing); return EventHandler.Action.CONTINUE; } }); final EventDetector monitored = logger.monitorDetector(ed); final Handler dayToNightHandler = new Handler(dayObservationLaw, nightRestingLaw); final Handler nightToDayHandler = new Handler(nightRestingLaw, dayObservationLaw); attitudesSequence.addSwitchingCondition(dayObservationLaw, nightRestingLaw, monitored, false, true, 300.0, AngularDerivativesFilter.USE_RRA, dayToNightHandler); attitudesSequence.addSwitchingCondition(nightRestingLaw, dayObservationLaw, monitored, true, false, 300.0, AngularDerivativesFilter.USE_RRA, nightToDayHandler); if (ed.g(new SpacecraftState(initialOrbit)) >= 0) { // initial position is in daytime setInEclipse(initialDate, false); attitudesSequence.resetActiveProvider(dayObservationLaw); } else { // initial position is in nighttime setInEclipse(initialDate, true); attitudesSequence.resetActiveProvider(nightRestingLaw); } // Propagator : consider the analytical Eckstein-Hechler model final Propagator propagator = new EcksteinHechlerPropagator(initialOrbit, attitudesSequence, Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20, Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40, Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60); // Register the switching events to the propagator attitudesSequence.registerSwitchEvents(propagator); propagator.setMasterMode(60.0, new OrekitFixedStepHandler() { public void init(final SpacecraftState s0, final AbsoluteDate t) { } public void handleStep(SpacecraftState currentState, boolean isLast) throws PropagationException { try { // the Earth position in spacecraft frame should be along spacecraft Z axis // during night time and away from it during day time due to roll and pitch offsets final Vector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO); final double pointingOffset = Vector3D.angle(earth, Vector3D.PLUS_K); // the g function is the eclipse indicator, its an angle between Sun and Earth limb, // positive when Sun is outside of Earth limb, negative when Sun is hidden by Earth limb final double eclipseAngle = ed.g(currentState); if (currentState.getDate().durationFrom(lastChange) > 300) { if (inEclipse) { Assert.assertTrue(eclipseAngle <= 0); Assert.assertEquals(0.0, pointingOffset, 1.0e-6); } else { Assert.assertTrue(eclipseAngle >= 0); Assert.assertEquals(0.767215, pointingOffset, 1.0e-6); } } else { // we are in transition Assert.assertTrue(pointingOffset + " " + (0.767215 - pointingOffset), pointingOffset <= 0.7672155); } } catch (OrekitException oe) { throw new PropagationException(oe); } } }); // Propagate from the initial date for the fixed duration propagator.propagate(initialDate.shiftedBy(12600.)); // as we have 2 switch events (even if they share the same underlying event detector), // and these events are triggered at both eclipse entry and exit, we get 8 // raw events on 2 orbits Assert.assertEquals(8, logger.getLoggedEvents().size()); // we have 4 attitudes switch on 2 orbits, 2 of each type Assert.assertEquals(2, dayToNightHandler.dates.size()); Assert.assertEquals(2, nightToDayHandler.dates.size()); } @Test public void testBackwardPropagation() throws OrekitException { // Initial state definition : date, orbit final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), initialDate, Constants.EIGEN5C_EARTH_MU); final AttitudesSequence attitudesSequence = new AttitudesSequence(); final AttitudeProvider past = new InertialProvider(Rotation.IDENTITY); final AttitudeProvider current = new InertialProvider(Rotation.IDENTITY); final AttitudeProvider future = new InertialProvider(Rotation.IDENTITY); final Handler handler = new Handler(current, past); attitudesSequence.addSwitchingCondition(past, current, new DateDetector(initialDate.shiftedBy(-500.0)), true, false, 10.0, AngularDerivativesFilter.USE_R, handler); attitudesSequence.addSwitchingCondition(current, future, new DateDetector(initialDate.shiftedBy(+500.0)), true, false, 10.0, AngularDerivativesFilter.USE_R, null); attitudesSequence.resetActiveProvider(current); final Propagator propagator = new EcksteinHechlerPropagator(initialOrbit, attitudesSequence, Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20, Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40, Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60); // Register the switching events to the propagator attitudesSequence.registerSwitchEvents(propagator); SpacecraftState finalState = propagator.propagate(initialDate.shiftedBy(-10000.0)); Assert.assertEquals(1, handler.dates.size()); Assert.assertEquals(-500.0, handler.dates.get(0).durationFrom(initialDate), 1.0e-3); Assert.assertEquals(-490.0, finalState.getDate().durationFrom(initialDate), 1.0e-3); } @Test public void testTooShortTransition() { double threshold = 1.5; double transitionTime = 0.5; try { new AttitudesSequence().addSwitchingCondition(new InertialProvider(Rotation.IDENTITY), new InertialProvider(Rotation.IDENTITY), new DateDetector(1000.0, threshold, AbsoluteDate.J2000_EPOCH), true, false, transitionTime, AngularDerivativesFilter.USE_R, null); Assert.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assert.assertEquals(OrekitMessages.TOO_SHORT_TRANSITION_TIME_FOR_ATTITUDES_SWITCH, oe.getSpecifier()); Assert.assertEquals(transitionTime, ((Double) oe.getParts()[0]).doubleValue(), 1.0e-10); Assert.assertEquals(threshold, ((Double) oe.getParts()[1]).doubleValue(), 1.0e-10); } } private static class Handler implements AttitudesSequence.SwitchHandler { private AttitudeProvider expectedPrevious; private AttitudeProvider expectedNext; private List<AbsoluteDate> dates; public Handler(final AttitudeProvider expectedPrevious, final AttitudeProvider expectedNext) { this.expectedPrevious = expectedPrevious; this.expectedNext = expectedNext; this.dates = new ArrayList<AbsoluteDate>(); } @Override public void switchOccurred(AttitudeProvider previous, AttitudeProvider next, SpacecraftState state) { Assert.assertTrue(previous == expectedPrevious); Assert.assertTrue(next == expectedNext); dates.add(state.getDate()); } } private void setInEclipse(AbsoluteDate lastChange, boolean inEclipse) { this.lastChange = lastChange; this.inEclipse = inEclipse; } @Before public void setUp() { Utils.setDataRoot("regular-data"); } }