fr.cs.examples.propagation.TrackCorridor.java Source code

Java tutorial

Introduction

Here is the source code for fr.cs.examples.propagation.TrackCorridor.java

Source

/* 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 fr.cs.examples.propagation;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.commons.math3.geometry.euclidean.threed.Line;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.util.FastMath;
import org.orekit.attitudes.LofOffset;
import org.orekit.bodies.BodyShape;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.errors.OrekitException;
import org.orekit.errors.PropagationException;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.frames.Transform;
import org.orekit.orbits.CircularOrbit;
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.EcksteinHechlerPropagator;
import org.orekit.propagation.analytical.tle.TLE;
import org.orekit.propagation.analytical.tle.TLEPropagator;
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.IERSConventions;
import org.orekit.utils.PVCoordinates;

import fr.cs.examples.Autoconfiguration;
import fr.cs.examples.KeyValueFileParser;

/** Orekit tutorial for track corridor display.
 * @author Luc Maisonobe
 */
public class TrackCorridor {

    /** Program entry point.
     * @param args program arguments
     */
    public static void main(String[] args) {
        try {

            // configure Orekit
            Autoconfiguration.configureOrekit();

            // input/out
            File input = new File(TrackCorridor.class.getResource("/track-corridor.in").toURI().getPath());
            File output = new File(input.getParentFile(), "track-corridor.csv");

            new TrackCorridor().run(input, output, ",");

            System.out.println("corridor saved as file " + output);

        } catch (URISyntaxException use) {
            System.err.println(use.getLocalizedMessage());
            System.exit(1);
        } catch (IOException ioe) {
            System.err.println(ioe.getLocalizedMessage());
            System.exit(1);
        } catch (IllegalArgumentException iae) {
            System.err.println(iae.getLocalizedMessage());
            System.exit(1);
        } catch (OrekitException oe) {
            System.err.println(oe.getLocalizedMessage());
            System.exit(1);
        }
    }

    /** Input parameter keys. */
    private static enum ParameterKey {

        TLE_LINE1, TLE_LINE2, ORBIT_CIRCULAR_DATE, ORBIT_CIRCULAR_A, ORBIT_CIRCULAR_EX, ORBIT_CIRCULAR_EY, ORBIT_CIRCULAR_I, ORBIT_CIRCULAR_RAAN, ORBIT_CIRCULAR_ALPHA, START_DATE, DURATION, STEP, ANGULAR_OFFSET;

    }

    private void run(final File input, final File output, final String separator)
            throws IOException, IllegalArgumentException, OrekitException {

        // read input parameters
        KeyValueFileParser<ParameterKey> parser = new KeyValueFileParser<ParameterKey>(ParameterKey.class);
        parser.parseInput(new FileInputStream(input));
        TimeScale utc = TimeScalesFactory.getUTC();

        Propagator propagator;
        if (parser.containsKey(ParameterKey.TLE_LINE1)) {
            propagator = createPropagator(parser.getString(ParameterKey.TLE_LINE1),
                    parser.getString(ParameterKey.TLE_LINE2));
        } else {
            propagator = createPropagator(parser.getDate(ParameterKey.ORBIT_CIRCULAR_DATE, utc),
                    parser.getDouble(ParameterKey.ORBIT_CIRCULAR_A),
                    parser.getDouble(ParameterKey.ORBIT_CIRCULAR_EX),
                    parser.getDouble(ParameterKey.ORBIT_CIRCULAR_EY),
                    parser.getAngle(ParameterKey.ORBIT_CIRCULAR_I),
                    parser.getAngle(ParameterKey.ORBIT_CIRCULAR_RAAN),
                    parser.getAngle(ParameterKey.ORBIT_CIRCULAR_ALPHA));
        }

        // simulation properties
        AbsoluteDate start = parser.getDate(ParameterKey.START_DATE, utc);
        double duration = parser.getDouble(ParameterKey.DURATION);
        double step = parser.getDouble(ParameterKey.STEP);
        double angle = parser.getAngle(ParameterKey.ANGULAR_OFFSET);

        // set up a handler to gather all corridor points
        CorridorHandler handler = new CorridorHandler(angle);
        propagator.setMasterMode(step, handler);

        // perform propagation, letting the step handler populate the corridor
        propagator.propagate(start, start.shiftedBy(duration));

        // retrieve the built corridor
        List<CorridorPoint> corridor = handler.getCorridor();

        // create a 7 columns csv file representing the corridor in the user home directory, with
        // date in column 1 (in ISO-8601 format)
        // left limit latitude in column 2 and left limit longitude in column 3
        // center track latitude in column 4 and center track longitude in column 5
        // right limit latitude in column 6 and right limit longitude in column 7
        DecimalFormat format = new DecimalFormat("#00.00000", new DecimalFormatSymbols(Locale.US));
        PrintStream stream = new PrintStream(output);
        for (CorridorPoint p : corridor) {
            stream.println(p.getDate() + separator + format.format(FastMath.toDegrees(p.getLeft().getLatitude()))
                    + separator + format.format(FastMath.toDegrees(p.getLeft().getLongitude())) + separator
                    + format.format(FastMath.toDegrees(p.getCenter().getLatitude())) + separator
                    + format.format(FastMath.toDegrees(p.getCenter().getLongitude())) + separator
                    + format.format(FastMath.toDegrees(p.getRight().getLatitude())) + separator
                    + format.format(FastMath.toDegrees(p.getRight().getLongitude())));
        }
        stream.close();

    }

    /** Create an orbit propagator for a circular orbit
     * @param a  semi-major axis (m)
     * @param ex e cos(), first component of circular eccentricity vector
     * @param ey e sin(), second component of circular eccentricity vector
     * @param i inclination (rad)
     * @param raan right ascension of ascending node (, rad)
     * @param alpha  an + , mean latitude argument (rad)
     * @param date date of the orbital parameters
     * @return an orbit propagator
     * @exception OrekitException if propagator cannot be built
     */
    private Propagator createPropagator(final AbsoluteDate date, final double a, final double ex, final double ey,
            final double i, final double raan, final double alpha) throws OrekitException {

        // create orbit
        Orbit initialOrbit = new CircularOrbit(a, ex, ey, i, raan, alpha, PositionAngle.MEAN,
                FramesFactory.getEME2000(), date, Constants.EIGEN5C_EARTH_MU);

        // create propagator
        Propagator propagator = new EcksteinHechlerPropagator(initialOrbit,
                new LofOffset(initialOrbit.getFrame(), LOFType.TNW), 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);

        return propagator;

    }

    /** Create an orbit propagator for a TLE orbit
     * @param line1 firs line of the TLE
     * @param line2 second line of the TLE
     * @return an orbit propagator
     * @exception OrekitException if the TLE lines are corrupted (wrong checksums ...)
     */
    private Propagator createPropagator(final String line1, final String line2) throws OrekitException {

        // create pseudo-orbit
        TLE tle = new TLE(line1, line2);

        // create propagator
        Propagator propagator = TLEPropagator.selectExtrapolator(tle);

        return propagator;

    }

    /** Step handler storing corridor points. */
    private static class CorridorHandler implements OrekitFixedStepHandler {

        /** Earth model. */
        private final BodyShape earth;

        /** Radial offset from satellite to some distant point at specified angular offset. */
        private final double deltaR;

        /** Cross-track offset from satellite to some distant point at specified angular offset. */
        private final double deltaC;

        /** Corridor. */
        private final List<CorridorPoint> corridor;

        /** simple constructor.
         * @param angle angular offset of corridor boundaries
         * @exception OrekitException if Earth frame cannot be built
         */
        public CorridorHandler(final double angle) throws OrekitException {

            // set up Earth model
            earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING,
                    FramesFactory.getITRF(IERSConventions.IERS_2010, false));

            // set up position offsets, using Earth radius as an arbitrary distance
            deltaR = Constants.WGS84_EARTH_EQUATORIAL_RADIUS * FastMath.cos(angle);
            deltaC = Constants.WGS84_EARTH_EQUATORIAL_RADIUS * FastMath.sin(angle);

            // prepare an empty corridor
            corridor = new ArrayList<TrackCorridor.CorridorPoint>();

        }

        /** {@inheritDoc} */
        public void init(final SpacecraftState s0, final AbsoluteDate t) {
        }

        /** {@inheritDoc} */
        public void handleStep(SpacecraftState currentState, boolean isLast) throws PropagationException {
            try {

                // compute sub-satellite track
                AbsoluteDate date = currentState.getDate();
                PVCoordinates pvInert = currentState.getPVCoordinates();
                Transform t = currentState.getFrame().getTransformTo(earth.getBodyFrame(), date);
                Vector3D p = t.transformPosition(pvInert.getPosition());
                Vector3D v = t.transformVector(pvInert.getVelocity());
                GeodeticPoint center = earth.transform(p, earth.getBodyFrame(), date);

                // compute left and right corridor points
                Vector3D nadir = p.normalize().negate();
                Vector3D crossTrack = p.crossProduct(v).normalize();
                Line leftLine = new Line(p, new Vector3D(1.0, p, deltaR, nadir, deltaC, crossTrack), 1.0e-10);
                GeodeticPoint left = earth.getIntersectionPoint(leftLine, p, earth.getBodyFrame(), date);
                Line rightLine = new Line(p, new Vector3D(1.0, p, deltaR, nadir, -deltaC, crossTrack), 1.0e-10);
                GeodeticPoint right = earth.getIntersectionPoint(rightLine, p, earth.getBodyFrame(), date);

                // add the corridor points
                corridor.add(new CorridorPoint(date, left, center, right));

            } catch (OrekitException oe) {
                throw new PropagationException(oe);
            }
        }

        /** Get the corridor.
         * @return build corridor
         */
        public List<CorridorPoint> getCorridor() {
            return corridor;
        }

    }

    /** Container for corridor points. */
    private static class CorridorPoint {

        /** Point date. */
        private final AbsoluteDate date;

        /** Left limit. */
        private final GeodeticPoint left;

        /** Central track point. */
        private final GeodeticPoint center;

        /** Right limit. */
        private final GeodeticPoint right;

        /** Simple constructor.
         * @param date point date
         * @param left left limit
         * @param center central track point
         * @param right right limit
         */
        public CorridorPoint(AbsoluteDate date, GeodeticPoint left, GeodeticPoint center, GeodeticPoint right) {
            this.date = date;
            this.left = left;
            this.center = center;
            this.right = right;
        }

        /** Get point date. */
        public AbsoluteDate getDate() {
            return date;
        }

        /** Get left limit. */
        public GeodeticPoint getLeft() {
            return left;
        }

        /** Get central track point. */
        public GeodeticPoint getCenter() {
            return center;
        }

        /** Get right limit. */
        public GeodeticPoint getRight() {
            return right;
        }

    }

}