1   /* Copyright 2002-2025 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  
21  import org.orekit.annotation.DefaultDataContext;
22  import org.orekit.data.DataContext;
23  import org.orekit.forces.ForceModel;
24  import org.orekit.forces.ForceModelModifier;
25  import org.orekit.forces.gravity.potential.CachedNormalizedSphericalHarmonicsProvider;
26  import org.orekit.forces.gravity.potential.GravityFields;
27  import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
28  import org.orekit.forces.gravity.potential.OceanTidesWave;
29  import org.orekit.frames.Frame;
30  import org.orekit.time.TimeScales;
31  import org.orekit.time.UT1Scale;
32  import org.orekit.utils.Constants;
33  import org.orekit.utils.IERSConventions;
34  import org.orekit.utils.OrekitConfiguration;
35  
36  /** Ocean tides force model.
37   * @since 6.1
38   * @author Luc Maisonobe
39   */
40  public class OceanTides implements ForceModelModifier {
41  
42      /** Default step for tides field sampling (seconds). */
43      public static final double DEFAULT_STEP = 600.0;
44  
45      /** Default number of points tides field sampling. */
46      public static final int DEFAULT_POINTS = 12;
47  
48      /** Underlying attraction model. */
49      private final ForceModel attractionModel;
50  
51      /** Simple constructor.
52       * <p>
53       * This constructor uses pole tides, the default {@link #DEFAULT_STEP step} and default
54       * {@link #DEFAULT_POINTS number of points} for the tides field interpolation.
55       * </p>
56       *
57       * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
58       *
59       * @param centralBodyFrame rotating body frame
60       * @param ae central body reference radius
61       * @param mu central body attraction coefficient
62       * @param degree degree of the tide model to load
63       * @param order order of the tide model to load
64       * @param conventions IERS conventions used for loading ocean pole tide
65       * @param ut1 UT1 time scale
66       * @see #DEFAULT_STEP
67       * @see #DEFAULT_POINTS
68       * @see #OceanTides(Frame, double, double, boolean, double, int, int, int, IERSConventions, UT1Scale)
69       * @see GravityFields#getOceanTidesWaves(int, int)
70       * @see #OceanTides(Frame, double, double, boolean, double, int, int, int,
71       * IERSConventions, UT1Scale, GravityFields)
72       */
73      @DefaultDataContext
74      public OceanTides(final Frame centralBodyFrame, final double ae, final double mu,
75                        final int degree, final int order,
76                        final IERSConventions conventions, final UT1Scale ut1) {
77          this(centralBodyFrame, ae, mu, true,
78               DEFAULT_STEP, DEFAULT_POINTS, degree, order,
79               conventions, ut1);
80      }
81  
82      /** Simple constructor.
83       *
84       * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
85       *
86       * @param centralBodyFrame rotating body frame
87       * @param ae central body reference radius
88       * @param mu central body attraction coefficient
89       * @param poleTide if true, pole tide is computed
90       * @param step time step between sample points for interpolation
91       * @param nbPoints number of points to use for interpolation, if less than 2
92       * then no interpolation is performed (thus greatly increasing computation cost)
93       * @param degree degree of the tide model to load
94       * @param order order of the tide model to load
95       * @param conventions IERS conventions used for loading ocean pole tide
96       * @param ut1 UT1 time scale
97       * @see GravityFields#getOceanTidesWaves(int, int)
98       * @see #OceanTides(Frame, double, double, boolean, double, int, int, int,
99       * IERSConventions, UT1Scale, GravityFields)
100      */
101     @DefaultDataContext
102     public OceanTides(final Frame centralBodyFrame, final double ae, final double mu,
103                       final boolean poleTide, final double step, final int nbPoints,
104                       final int degree, final int order,
105                       final IERSConventions conventions, final UT1Scale ut1) {
106         this(centralBodyFrame, ae, mu, poleTide, step, nbPoints, degree, order,
107                 conventions, ut1, DataContext.getDefault().getGravityFields());
108     }
109 
110     /** Simple constructor.
111      * @param centralBodyFrame rotating body frame
112      * @param ae central body reference radius
113      * @param mu central body attraction coefficient
114      * @param poleTide if true, pole tide is computed
115      * @param step time step between sample points for interpolation
116      * @param nbPoints number of points to use for interpolation, if less than 2
117      * then no interpolation is performed (thus greatly increasing computation cost)
118      * @param degree degree of the tide model to load
119      * @param order order of the tide model to load
120      * @param conventions IERS conventions used for loading ocean pole tide
121      * @param ut1 UT1 time scale
122      * @param gravityFields used to compute ocean tides.
123      * @see GravityFields#getOceanTidesWaves(int, int)
124      * @since 10.1
125      */
126     public OceanTides(final Frame centralBodyFrame, final double ae, final double mu,
127                       final boolean poleTide, final double step, final int nbPoints,
128                       final int degree, final int order,
129                       final IERSConventions conventions, final UT1Scale ut1,
130                       final GravityFields gravityFields) {
131 
132         // load the ocean tides model
133         final List<OceanTidesWave> waves = gravityFields.getOceanTidesWaves(degree, order);
134 
135         final TimeScales timeScales = ut1.getEOPHistory().getTimeScales();
136         final OceanTidesField raw =
137                 new OceanTidesField(ae, mu, waves,
138                                     conventions.getNutationArguments(ut1, timeScales),
139                                     poleTide ? conventions.getOceanPoleTide(ut1.getEOPHistory()) : null);
140 
141         final NormalizedSphericalHarmonicsProvider provider;
142         if (nbPoints < 2) {
143             provider = raw;
144         } else {
145             provider =
146                 new CachedNormalizedSphericalHarmonicsProvider(raw, step, nbPoints,
147                                                                OrekitConfiguration.getCacheSlotsNumber(),
148                                                                7 * Constants.JULIAN_DAY,
149                                                                0.5 * Constants.JULIAN_DAY);
150         }
151 
152         attractionModel = new HolmesFeatherstoneAttractionModel(centralBodyFrame, provider);
153 
154     }
155 
156     @Override
157     public ForceModel getUnderlyingModel() {
158         return attractionModel;
159     }
160 
161 }