ConstantThrustManeuver.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.forces.maneuvers;

  18. import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
  19. import org.apache.commons.math3.geometry.euclidean.threed.FieldRotation;
  20. import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
  21. import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
  22. import org.apache.commons.math3.ode.AbstractParameterizable;
  23. import org.orekit.errors.OrekitException;
  24. import org.orekit.errors.OrekitMessages;
  25. import org.orekit.forces.ForceModel;
  26. import org.orekit.frames.Frame;
  27. import org.orekit.propagation.SpacecraftState;
  28. import org.orekit.propagation.events.DateDetector;
  29. import org.orekit.propagation.events.EventDetector;
  30. import org.orekit.propagation.events.handlers.EventHandler;
  31. import org.orekit.propagation.numerical.TimeDerivativesEquations;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.utils.Constants;

  34. /** This class implements a simple maneuver with constant thrust.
  35.  * <p>The maneuver is defined by a direction in satelliteframe.
  36.  * The current attitude of the spacecraft, defined by the current
  37.  * spacecraft state, will be used to compute the thrust direction in
  38.  * inertial frame. A typical case for tangential maneuvers is to use a
  39.  * {@link org.orekit.attitudes.LofOffset LOF aligned} attitude provider for state propagation and a
  40.  * velocity increment along the +X satellite axis.</p>
  41.  * @author Fabien Maussion
  42.  * @author V&eacute;ronique Pommier-Maurussane
  43.  * @author Luc Maisonobe
  44.  */
  45. public class ConstantThrustManeuver extends AbstractParameterizable implements ForceModel {

  46.     /** Parameter name for thrust. */
  47.     private static final String THRUST = "thrust";

  48.     /** Parameter name for flow rate. */
  49.     private static final String FLOW_RATE = "flow rate";

  50.     /** State of the engine. */
  51.     private boolean firing;

  52.     /** Start of the maneuver. */
  53.     private final AbsoluteDate startDate;

  54.     /** End of the maneuver. */
  55.     private final AbsoluteDate endDate;

  56.     /** Engine thrust. */
  57.     private double thrust;

  58.     /** Engine flow-rate. */
  59.     private double flowRate;

  60.     /** Direction of the acceleration in satellite frame. */
  61.     private final Vector3D direction;

  62.     /** Simple constructor for a constant direction and constant thrust.
  63.      * @param date maneuver date
  64.      * @param duration the duration of the thrust (s) (if negative,
  65.      * the date is considered to be the stop date)
  66.      * @param thrust the thrust force (N)
  67.      * @param isp engine specific impulse (s)
  68.      * @param direction the acceleration direction in satellite frame.
  69.      */
  70.     public ConstantThrustManeuver(final AbsoluteDate date, final double duration,
  71.                                   final double thrust, final double isp,
  72.                                   final Vector3D direction) {

  73.         super(THRUST, FLOW_RATE);
  74.         if (duration >= 0) {
  75.             this.startDate = date;
  76.             this.endDate   = date.shiftedBy(duration);
  77.         } else {
  78.             this.endDate   = date;
  79.             this.startDate = endDate.shiftedBy(duration);
  80.         }

  81.         this.thrust    = thrust;
  82.         this.flowRate  = -thrust / (Constants.G0_STANDARD_GRAVITY * isp);
  83.         this.direction = direction.normalize();
  84.         firing = false;

  85.     }

  86.     /** Get the thrust.
  87.      * @return thrust force (N).
  88.      */
  89.     public double getThrust() {
  90.         return thrust;
  91.     }

  92.     /** Get the specific impulse.
  93.      * @return specific impulse (s).
  94.      */
  95.     public double getISP() {
  96.         return -thrust / (Constants.G0_STANDARD_GRAVITY * flowRate);
  97.     }

  98.     /** Get the flow rate.
  99.      * @return flow rate (negative, kg/s).
  100.      */
  101.     public double getFlowRate() {
  102.         return flowRate;
  103.     }

  104.     /** {@inheritDoc} */
  105.     public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder)
  106.         throws OrekitException {

  107.         if (firing) {

  108.             // compute thrust acceleration in inertial frame
  109.             adder.addAcceleration(new Vector3D(thrust / s.getMass(),
  110.                                                s.getAttitude().getRotation().applyInverseTo(direction)),
  111.                                   s.getFrame());

  112.             // compute flow rate
  113.             adder.addMassDerivative(flowRate);

  114.         }

  115.     }

  116.     /** {@inheritDoc} */
  117.     public FieldVector3D<DerivativeStructure> accelerationDerivatives(final AbsoluteDate date, final Frame frame,
  118.                                                                       final FieldVector3D<DerivativeStructure> position,
  119.                                                                       final FieldVector3D<DerivativeStructure> velocity,
  120.                                                                       final FieldRotation<DerivativeStructure> rotation,
  121.                                                                       final DerivativeStructure mass)
  122.         throws OrekitException {
  123.         if (firing) {
  124.             return new FieldVector3D<DerivativeStructure>(mass.reciprocal().multiply(thrust),
  125.                     rotation.applyInverseTo(direction));
  126.         } else {
  127.             // constant (and null) acceleration when not firing
  128.             final int parameters = mass.getFreeParameters();
  129.             final int order      = mass.getOrder();
  130.             return new FieldVector3D<DerivativeStructure>(new DerivativeStructure(parameters, order, 0.0),
  131.                     new DerivativeStructure(parameters, order, 0.0),
  132.                     new DerivativeStructure(parameters, order, 0.0));
  133.         }
  134.     }

  135.     /** {@inheritDoc} */
  136.     public FieldVector3D<DerivativeStructure> accelerationDerivatives(final SpacecraftState s, final String paramName)
  137.         throws OrekitException {

  138.         complainIfNotSupported(paramName);

  139.         if (firing) {

  140.             if (THRUST.equals(paramName)) {
  141.                 final DerivativeStructure thrustDS = new DerivativeStructure(1, 1, 0, thrust);
  142.                 return new FieldVector3D<DerivativeStructure>(thrustDS.divide(s.getMass()),
  143.                                                               s.getAttitude().getRotation().applyInverseTo(direction));
  144.             } else if (FLOW_RATE.equals(paramName)) {
  145.                 // acceleration does not depend on flow rate (only mass decrease does)
  146.                 final DerivativeStructure zero = new DerivativeStructure(1, 1, 0.0);
  147.                 return new FieldVector3D<DerivativeStructure>(zero, zero, zero);
  148.             } else {
  149.                 throw new OrekitException(OrekitMessages.UNSUPPORTED_PARAMETER_NAME, paramName,
  150.                                           THRUST + ", " + FLOW_RATE);
  151.             }

  152.         } else {
  153.             // constant (and null) acceleration when not firing
  154.             final DerivativeStructure zero = new DerivativeStructure(1, 1, 0.0);
  155.             return new FieldVector3D<DerivativeStructure>(zero, zero, zero);
  156.         }

  157.     }

  158.     /** {@inheritDoc} */
  159.     public EventDetector[] getEventsDetectors() {
  160.         return new EventDetector[] {
  161.             new DateDetector(startDate).withHandler(new FiringStartHandler()),
  162.             new DateDetector(endDate).withHandler(new FiringStopHandler())
  163.         };
  164.     }

  165.     /** {@inheritDoc} */
  166.     public double getParameter(final String name)
  167.         throws IllegalArgumentException {
  168.         complainIfNotSupported(name);
  169.         if (name.equals(THRUST)) {
  170.             return thrust;
  171.         }
  172.         return flowRate;
  173.     }

  174.     /** {@inheritDoc} */
  175.     public void setParameter(final String name, final double value)
  176.         throws IllegalArgumentException {
  177.         complainIfNotSupported(name);
  178.         if (name.equals(THRUST)) {
  179.             thrust = value;
  180.         } else {
  181.             flowRate = value;
  182.         }
  183.     }

  184.     /** Handler for start of maneuver. */
  185.     private class FiringStartHandler implements EventHandler<DateDetector> {

  186.         /** {@inheritDoc} */
  187.         @Override
  188.         public EventHandler.Action eventOccurred(final SpacecraftState s,
  189.                                                  final DateDetector detector,
  190.                                                  final boolean increasing) {
  191.             // start the maneuver
  192.             firing = true;
  193.             return EventHandler.Action.RESET_DERIVATIVES;
  194.         }

  195.         /** {@inheritDoc} */
  196.         @Override
  197.         public SpacecraftState resetState(final DateDetector detector, final SpacecraftState oldState) {
  198.             return oldState;
  199.         }

  200.     }

  201.     /** Handler for end of maneuver. */
  202.     private class FiringStopHandler implements EventHandler<DateDetector> {

  203.         /** {@inheritDoc} */
  204.         public EventHandler.Action eventOccurred(final SpacecraftState s,
  205.                                                  final DateDetector detector,
  206.                                                  final boolean increasing) {
  207.             // stop the maneuver
  208.             firing = false;
  209.             return EventHandler.Action.RESET_DERIVATIVES;
  210.         }

  211.         /** {@inheritDoc} */
  212.         @Override
  213.         public SpacecraftState resetState(final DateDetector detector, final SpacecraftState oldState) {
  214.             return oldState;
  215.         }

  216.     }

  217. }