AbstractDragForceModel.java

  1. /* Copyright 2002-2020 CS GROUP
  2.  * Licensed to CS GROUP (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.drag;

  18. import org.hipparchus.RealFieldElement;
  19. import org.hipparchus.analysis.differentiation.DSFactory;
  20. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  21. import org.hipparchus.analysis.differentiation.Gradient;
  22. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  23. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  24. import org.orekit.forces.AbstractForceModel;
  25. import org.orekit.frames.Frame;
  26. import org.orekit.frames.Transform;
  27. import org.orekit.models.earth.atmosphere.Atmosphere;
  28. import org.orekit.propagation.FieldSpacecraftState;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.time.FieldAbsoluteDate;
  31. import org.orekit.utils.FieldPVCoordinates;

  32. /**
  33.  * Base class for drag force models.
  34.  * @see DragForce
  35.  * @see TimeSpanDragForce
  36.  * @author Bryan Cazabonne
  37.  * @since 10.2
  38.  */
  39. public abstract class AbstractDragForceModel extends AbstractForceModel {

  40.     /** Atmospheric model. */
  41.     private final Atmosphere atmosphere;

  42.     /**
  43.      * Constructor.
  44.      * @param atmosphere atmospheric model
  45.      */
  46.     protected AbstractDragForceModel(final Atmosphere atmosphere) {
  47.         this.atmosphere = atmosphere;
  48.     }

  49.     /** {@inheritDoc} */
  50.     @Override
  51.     public boolean dependsOnPositionOnly() {
  52.         return false;
  53.     }

  54.     /** Check if a field state corresponds to derivatives with respect to state.
  55.      * @param state state to check
  56.      * @param <T> type of the field elements
  57.      * @return true if state corresponds to derivatives with respect to state
  58.      */
  59.     protected <T extends RealFieldElement<T>> boolean isDSStateDerivative(final FieldSpacecraftState<T> state) {
  60.         try {
  61.             final DerivativeStructure dsMass = (DerivativeStructure) state.getMass();
  62.             final int o = dsMass.getOrder();
  63.             final int p = dsMass.getFreeParameters();

  64.             // To be in the desired case:
  65.             // Order must be 1 (first order derivatives only)
  66.             // Number of parameters must be 6 (PV), 7 (PV + drag coefficient) or 8 (PV + drag coefficient + lift ratio)
  67.             if (o != 1 || (p != 6 && p != 7 && p != 8)) {
  68.                 return false;
  69.             }

  70.             // Check that the first 6 parameters are position and velocity
  71.             @SuppressWarnings("unchecked")
  72.             final FieldPVCoordinates<DerivativeStructure> pv = (FieldPVCoordinates<DerivativeStructure>) state.getPVCoordinates();
  73.             return isVariable(pv.getPosition().getX(), 0) &&
  74.                    isVariable(pv.getPosition().getY(), 1) &&
  75.                    isVariable(pv.getPosition().getZ(), 2) &&
  76.                    isVariable(pv.getVelocity().getX(), 3) &&
  77.                    isVariable(pv.getVelocity().getY(), 4) &&
  78.                    isVariable(pv.getVelocity().getZ(), 5);
  79.         } catch (ClassCastException cce) {
  80.             return false;
  81.         }
  82.     }

  83.     /** Check if a field state corresponds to derivatives with respect to state.
  84.      * @param state state to check
  85.      * @param <T> type of the field elements
  86.      * @return true if state corresponds to derivatives with respect to state
  87.      */
  88.     protected <T extends RealFieldElement<T>> boolean isGradientStateDerivative(final FieldSpacecraftState<T> state) {
  89.         try {
  90.             final Gradient gMass = (Gradient) state.getMass();
  91.             final int p = gMass.getFreeParameters();

  92.             // To be in the desired case:
  93.             // Number of parameters must be 6 (PV), 7 (PV + drag coefficient) or 8 (PV + drag coefficient + lift ratio)
  94.             if (p != 6 && p != 7 && p != 8) {
  95.                 return false;
  96.             }

  97.             // Check that the first 6 parameters are position and velocity
  98.             @SuppressWarnings("unchecked")
  99.             final FieldPVCoordinates<Gradient> pv = (FieldPVCoordinates<Gradient>) state.getPVCoordinates();
  100.             return isVariable(pv.getPosition().getX(), 0) &&
  101.                    isVariable(pv.getPosition().getY(), 1) &&
  102.                    isVariable(pv.getPosition().getZ(), 2) &&
  103.                    isVariable(pv.getVelocity().getX(), 3) &&
  104.                    isVariable(pv.getVelocity().getY(), 4) &&
  105.                    isVariable(pv.getVelocity().getZ(), 5);
  106.         } catch (ClassCastException cce) {
  107.             return false;
  108.         }
  109.     }

  110.     /** Check if a derivative represents a specified variable.
  111.      * @param ds derivative to check
  112.      * @param index index of the variable
  113.      * @return true if the derivative represents a specified variable
  114.      */
  115.     protected boolean isVariable(final DerivativeStructure ds, final int index) {
  116.         final double[] derivatives = ds.getAllDerivatives();
  117.         boolean check = true;
  118.         for (int i = 1; i < derivatives.length; ++i) {
  119.             check &= derivatives[i] == ((index + 1 == i) ? 1.0 : 0.0);
  120.         }
  121.         return check;
  122.     }

  123.     /** Check if a derivative represents a specified variable.
  124.      * @param g derivative to check
  125.      * @param index index of the variable
  126.      * @return true if the derivative represents a specified variable
  127.      */
  128.     protected boolean isVariable(final Gradient g, final int index) {
  129.         final double[] derivatives = g.getGradient();
  130.         boolean check = true;
  131.         for (int i = 0; i < derivatives.length; ++i) {
  132.             check &= derivatives[i] == ((index == i) ? 1.0 : 0.0);
  133.         }
  134.         return check;
  135.     }

  136.     /** Compute density and its derivatives.
  137.      * Using finite differences for the derivatives.
  138.      * And doing the actual computation only for the derivatives with respect to position (others are set to 0.).
  139.      * <p>
  140.      * From a theoretical point of view, this method computes the same values
  141.      * as {@link Atmosphere#getDensity(FieldAbsoluteDate, FieldVector3D, Frame)} in the
  142.      * specific case of {@link DerivativeStructure} with respect to state, so
  143.      * it is less general. However, it is *much* faster in this important case.
  144.      * </p>
  145.      * <p>
  146.      * The derivatives should be computed with respect to position. The input
  147.      * parameters already take into account the free parameters (6, 7 or 8 depending
  148.      * on derivation with respect to drag coefficient and lift ratio being considered or not)
  149.      * and order (always 1). Free parameters at indices 0, 1 and 2 correspond to derivatives
  150.      * with respect to position. Free parameters at indices 3, 4 and 5 correspond
  151.      * to derivatives with respect to velocity (these derivatives will remain zero
  152.      * as the atmospheric density does not depend on velocity). Free parameter
  153.      * at indexes 6 and 7 (if present) corresponds to derivatives with respect to drag coefficient
  154.      * and/or lift ratio (one of these or both).
  155.      * This 2 last derivatives will remain zero as atmospheric density does not depend on them.
  156.      * </p>
  157.      * @param date current date
  158.      * @param frame inertial reference frame for state (both orbit and attitude)
  159.      * @param position position of spacecraft in inertial frame
  160.      * @return the density and its derivatives
  161.      */
  162.     protected DerivativeStructure getDSDensityWrtStateUsingFiniteDifferences(final AbsoluteDate date,
  163.                                                                              final Frame frame,
  164.                                                                              final FieldVector3D<DerivativeStructure> position) {

  165.         // Retrieve derivation properties for parameter T
  166.         // It is implied here that T is a DerivativeStructure
  167.         // With order 1 and 6, 7 or 8 free parameters
  168.         // This is all checked before in method isStateDerivatives
  169.         final DSFactory factory = position.getX().getFactory();

  170.         // Build a DerivativeStructure using only derivatives with respect to position
  171.         final DSFactory factory3 = new DSFactory(3, 1);
  172.         final FieldVector3D<DerivativeStructure> position3 =
  173.                         new FieldVector3D<>(factory3.variable(0, position.getX().getReal()),
  174.                                             factory3.variable(1,  position.getY().getReal()),
  175.                                             factory3.variable(2,  position.getZ().getReal()));

  176.         // Get atmosphere properties in atmosphere own frame
  177.         final Frame      atmFrame  = atmosphere.getFrame();
  178.         final Transform  toBody    = frame.getTransformTo(atmFrame, date);
  179.         final FieldVector3D<DerivativeStructure> posBodyDS = toBody.transformPosition(position3);
  180.         final Vector3D   posBody   = posBodyDS.toVector3D();

  181.         // Estimate density model by finite differences and composition
  182.         // Using a delta of 1m
  183.         final double delta  = 1.0;
  184.         final double x      = posBody.getX();
  185.         final double y      = posBody.getY();
  186.         final double z      = posBody.getZ();
  187.         final double rho0   = atmosphere.getDensity(date, posBody, atmFrame);
  188.         final double dRhodX = (atmosphere.getDensity(date, new Vector3D(x + delta, y,         z),         atmFrame) - rho0) / delta;
  189.         final double dRhodY = (atmosphere.getDensity(date, new Vector3D(x,         y + delta, z),         atmFrame) - rho0) / delta;
  190.         final double dRhodZ = (atmosphere.getDensity(date, new Vector3D(x,         y,         z + delta), atmFrame) - rho0) / delta;
  191.         final double[] dXdQ = posBodyDS.getX().getAllDerivatives();
  192.         final double[] dYdQ = posBodyDS.getY().getAllDerivatives();
  193.         final double[] dZdQ = posBodyDS.getZ().getAllDerivatives();

  194.         // Density with derivatives:
  195.         // - The value and only the 3 first derivatives (those with respect to spacecraft position) are computed
  196.         // - Others are set to 0.
  197.         final int p = factory.getCompiler().getFreeParameters();
  198.         final double[] rhoAll = new double[p + 1];
  199.         rhoAll[0] = rho0;
  200.         for (int i = 1; i < 4; ++i) {
  201.             rhoAll[i] = dRhodX * dXdQ[i] + dRhodY * dYdQ[i] + dRhodZ * dZdQ[i];
  202.         }

  203.         return factory.build(rhoAll);
  204.     }

  205.     /** Compute density and its derivatives.
  206.      * Using finite differences for the derivatives.
  207.      * And doing the actual computation only for the derivatives with respect to position (others are set to 0.).
  208.      * <p>
  209.      * From a theoretical point of view, this method computes the same values
  210.      * as {@link Atmosphere#getDensity(FieldAbsoluteDate, FieldVector3D, Frame)} in the
  211.      * specific case of {@link Gradient} with respect to state, so
  212.      * it is less general. However, it is *much* faster in this important case.
  213.      * </p>
  214.      * <p>
  215.      * The derivatives should be computed with respect to position. The input
  216.      * parameters already take into account the free parameters (6, 7 or 8 depending
  217.      * on derivation with respect to drag coefficient and lift ratio being considered or not)
  218.      * and order (always 1). Free parameters at indices 0, 1 and 2 correspond to derivatives
  219.      * with respect to position. Free parameters at indices 3, 4 and 5 correspond
  220.      * to derivatives with respect to velocity (these derivatives will remain zero
  221.      * as the atmospheric density does not depend on velocity). Free parameter
  222.      * at indexes 6 and 7 (if present) corresponds to derivatives with respect to drag coefficient
  223.      * and/or lift ratio (one of these or both).
  224.      * This 2 last derivatives will remain zero as atmospheric density does not depend on them.
  225.      * </p>
  226.      * @param date current date
  227.      * @param frame inertial reference frame for state (both orbit and attitude)
  228.      * @param position position of spacecraft in inertial frame
  229.      * @return the density and its derivatives
  230.      */
  231.     protected Gradient getGradientDensityWrtStateUsingFiniteDifferences(final AbsoluteDate date,
  232.                                                                         final Frame frame,
  233.                                                                         final FieldVector3D<Gradient> position) {

  234.         // Build a Gradient using only derivatives with respect to position
  235.         final FieldVector3D<Gradient> position3 =
  236.                         new FieldVector3D<>(Gradient.variable(3, 0, position.getX().getReal()),
  237.                                             Gradient.variable(3, 1,  position.getY().getReal()),
  238.                                             Gradient.variable(3, 2,  position.getZ().getReal()));

  239.         // Get atmosphere properties in atmosphere own frame
  240.         final Frame      atmFrame  = atmosphere.getFrame();
  241.         final Transform  toBody    = frame.getTransformTo(atmFrame, date);
  242.         final FieldVector3D<Gradient> posBodyDS = toBody.transformPosition(position3);
  243.         final Vector3D   posBody   = posBodyDS.toVector3D();

  244.         // Estimate density model by finite differences and composition
  245.         // Using a delta of 1m
  246.         final double delta  = 1.0;
  247.         final double x      = posBody.getX();
  248.         final double y      = posBody.getY();
  249.         final double z      = posBody.getZ();
  250.         final double rho0   = atmosphere.getDensity(date, posBody, atmFrame);
  251.         final double dRhodX = (atmosphere.getDensity(date, new Vector3D(x + delta, y,         z),         atmFrame) - rho0) / delta;
  252.         final double dRhodY = (atmosphere.getDensity(date, new Vector3D(x,         y + delta, z),         atmFrame) - rho0) / delta;
  253.         final double dRhodZ = (atmosphere.getDensity(date, new Vector3D(x,         y,         z + delta), atmFrame) - rho0) / delta;
  254.         final double[] dXdQ = posBodyDS.getX().getGradient();
  255.         final double[] dYdQ = posBodyDS.getY().getGradient();
  256.         final double[] dZdQ = posBodyDS.getZ().getGradient();

  257.         // Density with derivatives:
  258.         // - The value and only the 3 first derivatives (those with respect to spacecraft position) are computed
  259.         // - Others are set to 0.
  260.         final int p = position.getX().getFreeParameters();
  261.         final double[] rhoAll = new double[p];
  262.         for (int i = 0; i < 3; ++i) {
  263.             rhoAll[i] = dRhodX * dXdQ[i] + dRhodY * dYdQ[i] + dRhodZ * dZdQ[i];
  264.         }

  265.         return new Gradient(rho0, rhoAll);
  266.     }

  267. }