1   /* Copyright 2002-2021 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.gravity;
18  
19  import java.util.List;
20  import java.util.stream.Stream;
21  
22  import org.hipparchus.Field;
23  import org.hipparchus.CalculusFieldElement;
24  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.orekit.annotation.DefaultDataContext;
27  import org.orekit.data.DataContext;
28  import org.orekit.forces.AbstractForceModel;
29  import org.orekit.forces.ForceModel;
30  import org.orekit.forces.gravity.potential.CachedNormalizedSphericalHarmonicsProvider;
31  import org.orekit.forces.gravity.potential.GravityFields;
32  import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
33  import org.orekit.forces.gravity.potential.OceanTidesWave;
34  import org.orekit.frames.Frame;
35  import org.orekit.propagation.FieldSpacecraftState;
36  import org.orekit.propagation.SpacecraftState;
37  import org.orekit.propagation.events.EventDetector;
38  import org.orekit.propagation.events.FieldEventDetector;
39  import org.orekit.time.TimeScales;
40  import org.orekit.time.UT1Scale;
41  import org.orekit.utils.Constants;
42  import org.orekit.utils.IERSConventions;
43  import org.orekit.utils.OrekitConfiguration;
44  import org.orekit.utils.ParameterDriver;
45  
46  /** Ocean tides force model.
47   * @since 6.1
48   * @author Luc Maisonobe
49   */
50  public class OceanTides extends AbstractForceModel {
51  
52      /** Default step for tides field sampling (seconds). */
53      public static final double DEFAULT_STEP = 600.0;
54  
55      /** Default number of points tides field sampling. */
56      public static final int DEFAULT_POINTS = 12;
57  
58      /** Underlying attraction model. */
59      private final ForceModel attractionModel;
60  
61      /** Simple constructor.
62       * <p>
63       * This constructor uses pole tides, the default {@link #DEFAULT_STEP step} and default
64       * {@link #DEFAULT_POINTS number of points} for the tides field interpolation.
65       * </p>
66       *
67       * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
68       *
69       * @param centralBodyFrame rotating body frame
70       * @param ae central body reference radius
71       * @param mu central body attraction coefficient
72       * @param degree degree of the tide model to load
73       * @param order order of the tide model to load
74       * @param conventions IERS conventions used for loading ocean pole tide
75       * @param ut1 UT1 time scale
76       * @see #DEFAULT_STEP
77       * @see #DEFAULT_POINTS
78       * @see #OceanTides(Frame, double, double, boolean, double, int, int, int, IERSConventions, UT1Scale)
79       * @see GravityFields#getOceanTidesWaves(int, int)
80       * @see #OceanTides(Frame, double, double, boolean, double, int, int, int,
81       * IERSConventions, UT1Scale, GravityFields)
82       */
83      @DefaultDataContext
84      public OceanTides(final Frame centralBodyFrame, final double ae, final double mu,
85                        final int degree, final int order,
86                        final IERSConventions conventions, final UT1Scale ut1) {
87          this(centralBodyFrame, ae, mu, true,
88               DEFAULT_STEP, DEFAULT_POINTS, degree, order,
89               conventions, ut1);
90      }
91  
92      /** Simple constructor.
93       *
94       * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
95       *
96       * @param centralBodyFrame rotating body frame
97       * @param ae central body reference radius
98       * @param mu central body attraction coefficient
99       * @param poleTide if true, pole tide is computed
100      * @param step time step between sample points for interpolation
101      * @param nbPoints number of points to use for interpolation, if less than 2
102      * then no interpolation is performed (thus greatly increasing computation cost)
103      * @param degree degree of the tide model to load
104      * @param order order of the tide model to load
105      * @param conventions IERS conventions used for loading ocean pole tide
106      * @param ut1 UT1 time scale
107      * @see GravityFields#getOceanTidesWaves(int, int)
108      * @see #OceanTides(Frame, double, double, boolean, double, int, int, int,
109      * IERSConventions, UT1Scale, GravityFields)
110      */
111     @DefaultDataContext
112     public OceanTides(final Frame centralBodyFrame, final double ae, final double mu,
113                       final boolean poleTide, final double step, final int nbPoints,
114                       final int degree, final int order,
115                       final IERSConventions conventions, final UT1Scale ut1) {
116         this(centralBodyFrame, ae, mu, poleTide, step, nbPoints, degree, order,
117                 conventions, ut1, DataContext.getDefault().getGravityFields());
118     }
119 
120     /** Simple constructor.
121      * @param centralBodyFrame rotating body frame
122      * @param ae central body reference radius
123      * @param mu central body attraction coefficient
124      * @param poleTide if true, pole tide is computed
125      * @param step time step between sample points for interpolation
126      * @param nbPoints number of points to use for interpolation, if less than 2
127      * then no interpolation is performed (thus greatly increasing computation cost)
128      * @param degree degree of the tide model to load
129      * @param order order of the tide model to load
130      * @param conventions IERS conventions used for loading ocean pole tide
131      * @param ut1 UT1 time scale
132      * @param gravityFields used to compute ocean tides.
133      * @see GravityFields#getOceanTidesWaves(int, int)
134      * @since 10.1
135      */
136     public OceanTides(final Frame centralBodyFrame, final double ae, final double mu,
137                       final boolean poleTide, final double step, final int nbPoints,
138                       final int degree, final int order,
139                       final IERSConventions conventions, final UT1Scale ut1,
140                       final GravityFields gravityFields) {
141 
142         // load the ocean tides model
143         final List<OceanTidesWave> waves = gravityFields.getOceanTidesWaves(degree, order);
144 
145         final TimeScales timeScales = ut1.getEOPHistory().getTimeScales();
146         final OceanTidesField raw =
147                 new OceanTidesField(ae, mu, waves,
148                                     conventions.getNutationArguments(ut1, timeScales),
149                                     poleTide ? conventions.getOceanPoleTide(ut1.getEOPHistory()) : null);
150 
151         final NormalizedSphericalHarmonicsProvider provider;
152         if (nbPoints < 2) {
153             provider = raw;
154         } else {
155             provider =
156                 new CachedNormalizedSphericalHarmonicsProvider(raw, step, nbPoints,
157                                                                OrekitConfiguration.getCacheSlotsNumber(),
158                                                                7 * Constants.JULIAN_DAY,
159                                                                0.5 * Constants.JULIAN_DAY);
160         }
161 
162         attractionModel = new HolmesFeatherstoneAttractionModel(centralBodyFrame, provider);
163 
164     }
165 
166     /** {@inheritDoc} */
167     @Override
168     public boolean dependsOnPositionOnly() {
169         return attractionModel.dependsOnPositionOnly();
170     }
171 
172     /** {@inheritDoc} */
173     @Override
174     public Vector3D acceleration(final SpacecraftState s, final double[] parameters) {
175         // delegate to underlying model
176         return attractionModel.acceleration(s, parameters);
177     }
178 
179     /** {@inheritDoc} */
180     @Override
181     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> s,
182                                                                          final T[] parameters) {
183         // delegate to underlying model
184         return attractionModel.acceleration(s, parameters);
185     }
186 
187 
188     /** {@inheritDoc} */
189     @Override
190     public Stream<EventDetector> getEventsDetectors() {
191         // delegate to underlying attraction model
192         return attractionModel.getEventsDetectors();
193     }
194 
195     /** {@inheritDoc} */
196     @Override
197     public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
198         // delegate to underlying attraction model
199         return attractionModel.getFieldEventsDetectors(field);
200     }
201 
202     /** {@inheritDoc} */
203     @Override
204     public List<ParameterDriver> getParametersDrivers() {
205         // delegate to underlying attraction model
206         return attractionModel.getParametersDrivers();
207     }
208 
209 }