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