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.propagation.semianalytical.dsst.forces;
18  
19  import org.hipparchus.Field;
20  import org.hipparchus.RealFieldElement;
21  import org.hipparchus.util.FastMath;
22  import org.hipparchus.util.MathArrays;
23  import org.hipparchus.util.MathUtils;
24  import org.orekit.forces.drag.DragForce;
25  import org.orekit.forces.drag.DragSensitive;
26  import org.orekit.forces.drag.IsotropicDrag;
27  import org.orekit.models.earth.atmosphere.Atmosphere;
28  import org.orekit.propagation.FieldSpacecraftState;
29  import org.orekit.propagation.SpacecraftState;
30  import org.orekit.propagation.events.EventDetector;
31  import org.orekit.propagation.events.FieldEventDetector;
32  import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
33  import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
34  import org.orekit.utils.Constants;
35  import org.orekit.utils.ParameterDriver;
36  
37  /** Atmospheric drag contribution to the
38   *  {@link org.orekit.propagation.semianalytical.dsst.DSSTPropagator DSSTPropagator}.
39   *  <p>
40   *  The drag acceleration is computed through the acceleration model of
41   *  {@link org.orekit.forces.drag.DragForce DragForce}.
42   *  </p>
43   *
44   * @author Pascal Parraud
45   */
46  public class DSSTAtmosphericDrag extends AbstractGaussianContribution {
47  
48      /** Threshold for the choice of the Gauss quadrature order. */
49      private static final double GAUSS_THRESHOLD = 6.0e-10;
50  
51      /** Upper limit for atmospheric drag (m) . */
52      private static final double ATMOSPHERE_ALTITUDE_MAX = 1000000.;
53  
54      /** Atmospheric drag force model. */
55      private final DragForce drag;
56  
57      /** Critical distance from the center of the central body for entering/leaving the atmosphere. */
58      private final double     rbar;
59  
60      /** Simple constructor with custom force.
61       * @param force atmospheric drag force model
62       * @param mu central attraction coefficient
63       */
64      public DSSTAtmosphericDrag(final DragForce force, final double mu) {
65          //Call to the constructor from superclass using the numerical drag model as ForceModel
66          super("DSST-drag-", GAUSS_THRESHOLD, force, mu);
67          this.drag = force;
68          this.rbar = ATMOSPHERE_ALTITUDE_MAX + Constants.WGS84_EARTH_EQUATORIAL_RADIUS;
69      }
70  
71      /** Simple constructor assuming spherical spacecraft.
72       * @param atmosphere atmospheric model
73       * @param cd drag coefficient
74       * @param area cross sectionnal area of satellite
75       * @param mu central attraction coefficient
76       */
77      public DSSTAtmosphericDrag(final Atmosphere atmosphere, final double cd,
78                                 final double area, final double mu) {
79          this(atmosphere, new IsotropicDrag(area, cd), mu);
80      }
81  
82      /** Simple constructor with custom spacecraft.
83       * @param atmosphere atmospheric model
84       * @param spacecraft spacecraft model
85       * @param mu central attraction coefficient
86       */
87      public DSSTAtmosphericDrag(final Atmosphere atmosphere, final DragSensitive spacecraft, final double mu) {
88  
89          //Call to the constructor from superclass using the numerical drag model as ForceModel
90          this(new DragForce(atmosphere, spacecraft), mu);
91      }
92  
93      /** Get the atmospheric model.
94       * @return atmosphere model
95       */
96      public Atmosphere getAtmosphere() {
97          return drag.getAtmosphere();
98      }
99  
100     /** Get the critical distance.
101      *  <p>
102      *  The critical distance from the center of the central body aims at
103      *  defining the atmosphere entry/exit.
104      *  </p>
105      *  @return the critical distance from the center of the central body (m)
106      */
107     public double getRbar() {
108         return rbar;
109     }
110 
111     /** {@inheritDoc} */
112     public EventDetector[] getEventsDetectors() {
113         return null;
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public <T extends RealFieldElement<T>> FieldEventDetector<T>[] getFieldEventsDetectors(final Field<T> field) {
119         return null;
120     }
121 
122     /** {@inheritDoc} */
123     protected double[] getLLimits(final SpacecraftState state, final AuxiliaryElements auxiliaryElements) {
124 
125         final double perigee = auxiliaryElements.getSma() * (1. - auxiliaryElements.getEcc());
126 
127         // Trajectory entirely out of the atmosphere
128         if (perigee > rbar) {
129             return new double[2];
130         }
131         final double apogee  = auxiliaryElements.getSma() * (1. + auxiliaryElements.getEcc());
132         // Trajectory entirely within of the atmosphere
133         if (apogee < rbar) {
134             return new double[] { -FastMath.PI + MathUtils.normalizeAngle(state.getLv(), 0),
135                                   FastMath.PI + MathUtils.normalizeAngle(state.getLv(), 0) };
136         }
137         // Else, trajectory partialy within of the atmosphere
138         final double fb = FastMath.acos(((auxiliaryElements.getSma() * (1. - auxiliaryElements.getEcc() * auxiliaryElements.getEcc()) / rbar) - 1.) / auxiliaryElements.getEcc());
139         final double wW = FastMath.atan2(auxiliaryElements.getH(), auxiliaryElements.getK());
140         return new double[] {wW - fb, wW + fb};
141     }
142 
143     /** {@inheritDoc} */
144     protected <T extends RealFieldElement<T>> T[] getLLimits(final FieldSpacecraftState<T> state,
145                                                              final FieldAuxiliaryElements<T> auxiliaryElements) {
146 
147         final Field<T> field = state.getDate().getField();
148         final T zero = field.getZero();
149 
150         final T[] tab = MathArrays.buildArray(field, 2);
151 
152         final T perigee = auxiliaryElements.getSma().multiply(auxiliaryElements.getEcc().negate().add(1.));
153         // Trajectory entirely out of the atmosphere
154         if (perigee.getReal() > rbar) {
155             return tab;
156         }
157         final T apogee  = auxiliaryElements.getSma().multiply(auxiliaryElements.getEcc().add(1.));
158         // Trajectory entirely within of the atmosphere
159         if (apogee.getReal() < rbar) {
160             tab[0] = MathUtils.normalizeAngle(state.getLv(), zero).subtract(FastMath.PI);
161             tab[1] = MathUtils.normalizeAngle(state.getLv(), zero).add(FastMath.PI);
162             return tab;
163         }
164         // Else, trajectory partialy within of the atmosphere
165         final T fb = FastMath.acos(((auxiliaryElements.getSma().multiply(auxiliaryElements.getEcc().multiply(auxiliaryElements.getEcc()).negate().add(1.)).divide(rbar)).subtract(1.)).divide(auxiliaryElements.getEcc()));
166         final T wW = FastMath.atan2(auxiliaryElements.getH(), auxiliaryElements.getK());
167 
168         tab[0] = wW.subtract(fb);
169         tab[1] = wW.add(fb);
170         return tab;
171     }
172 
173     /** {@inheritDoc} */
174     @Override
175     protected ParameterDriver[] getParametersDriversWithoutMu() {
176         return drag.getParametersDrivers();
177     }
178 
179     /** Get spacecraft shape.
180      *
181      * @return spacecraft shape
182      */
183     public DragSensitive getSpacecraft() {
184         return drag.getSpacecraft();
185     }
186 
187     /** Get drag force.
188      *
189      * @return drag force
190      */
191     public DragForce getDrag() {
192         return drag;
193     }
194 }