OceanTidesField.java
/* Copyright 2002-2024 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.forces.gravity;
import java.util.List;
import org.hipparchus.util.FastMath;
import org.orekit.data.BodiesElements;
import org.orekit.data.FundamentalNutationArguments;
import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
import org.orekit.forces.gravity.potential.OceanTidesWave;
import org.orekit.forces.gravity.potential.TideSystem;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeVectorFunction;
/** Gravity field corresponding to ocean tides.
* <p>
* This ocean tides force model implementation corresponds to the method described
* in <a href="http://www.iers.org/nn_11216/IERS/EN/Publications/TechnicalNotes/tn36.html">
* IERS conventions (2010)</a>, chapter 6, section 6.3.
* </p>
* <p>
* Note that this class is <em>not</em> thread-safe, and that tides computation
* are computer intensive if repeated. So this class is really expected to
* be wrapped within a {@link
* org.orekit.forces.gravity.potential.CachedNormalizedSphericalHarmonicsProvider}
* that will both ensure thread safety and improve performances using caching.
* </p>
* @see OceanTides
* @author Luc Maisonobe
* @since 6.1
*/
class OceanTidesField implements NormalizedSphericalHarmonicsProvider {
/** Maximum degree. */
private final int degree;
/** Maximum order. */
private final int order;
/** Central body reference radius. */
private final double ae;
/** Central body attraction coefficient. */
private final double mu;
/** Tides model. */
private final List<OceanTidesWave> waves;
/** Object computing the fundamental arguments. */
private final FundamentalNutationArguments arguments;
/** Function computing pole tide terms (ΔC₂₁, ΔS₂₁). */
private final TimeVectorFunction poleTideFunction;
/** Simple constructor.
* @param ae central body reference radius
* @param mu central body attraction coefficient
* @param waves ocean tides waves
* @param arguments object computing the fundamental arguments
* @param poleTideFunction function computing ocean pole tide terms (ΔC₂₁, ΔS₂₁), may be null
*/
OceanTidesField(final double ae, final double mu,
final List<OceanTidesWave> waves,
final FundamentalNutationArguments arguments,
final TimeVectorFunction poleTideFunction) {
// store mode parameters
this.ae = ae;
this.mu = mu;
// waves
this.waves = waves;
int m = 0;
int n = 0;
for (final OceanTidesWave wave : waves) {
m = FastMath.max(m, wave.getMaxDegree());
n = FastMath.max(n, wave.getMaxOrder());
}
degree = m;
order = n;
this.arguments = arguments;
// pole tide
this.poleTideFunction = poleTideFunction;
}
/** {@inheritDoc} */
@Override
public int getMaxDegree() {
return degree;
}
/** {@inheritDoc} */
@Override
public int getMaxOrder() {
return order;
}
/** {@inheritDoc} */
@Override
public double getMu() {
return mu;
}
/** {@inheritDoc} */
@Override
public double getAe() {
return ae;
}
/** {@inheritDoc} */
@Override
public AbsoluteDate getReferenceDate() {
return AbsoluteDate.ARBITRARY_EPOCH;
}
/** {@inheritDoc} */
@Override
public TideSystem getTideSystem() {
// not really used here, but for consistency we can state that either
// we add the permanent tide or it was already in the central attraction
return TideSystem.ZERO_TIDE;
}
/** {@inheritDoc} */
@Override
public NormalizedSphericalHarmonics onDate(final AbsoluteDate date) {
// computed Cnm and Snm coefficients
final int rows = degree + 1;
final double[][] cnm = new double[rows][];
final double[][] snm = new double[rows][];
for (int i = 0; i <= degree; ++i) {
final int m = FastMath.min(i, order) + 1;
cnm[i] = new double[m];
snm[i] = new double[m];
}
final BodiesElements bodiesElements = arguments.evaluateAll(date);
for (final OceanTidesWave wave : waves) {
wave.addContribution(bodiesElements, cnm, snm);
}
if (poleTideFunction != null && degree > 1 && order > 0) {
// add pole tide
poleTide(date, cnm, snm);
}
return new TideHarmonics(date, cnm, snm);
}
/** Update coefficients applying pole tide.
* @param date current date
* @param cnm the Cnm coefficients. Modified in place.
* @param snm the Snm coefficients. Modified in place.
*/
private void poleTide(final AbsoluteDate date, final double[][] cnm, final double[][] snm) {
final double[] deltaCS = poleTideFunction.value(date);
cnm[2][1] += deltaCS[0]; // ΔC₂₁
snm[2][1] += deltaCS[1]; // ΔS₂₁
}
/** The Tidal geopotential evaluated on a specific date. */
private static class TideHarmonics implements NormalizedSphericalHarmonics {
/** evaluation date. */
private final AbsoluteDate date;
/** Cached cnm. */
private final double[][] cnm;
/** Cached snm. */
private final double[][] snm;
/** Construct the tidal harmonics on the given date.
*
* @param date of evaluation
* @param cnm the Cnm coefficients. Not copied.
* @param snm the Snm coeffiecients. Not copied.
*/
private TideHarmonics(final AbsoluteDate date,
final double[][] cnm,
final double[][] snm) {
this.date = date;
this.cnm = cnm;
this.snm = snm;
}
/** {@inheritDoc} */
@Override
public AbsoluteDate getDate() {
return date;
}
/** {@inheritDoc} */
@Override
public double getNormalizedCnm(final int n, final int m) {
return cnm[n][m];
}
/** {@inheritDoc} */
@Override
public double getNormalizedSnm(final int n, final int m) {
return snm[n][m];
}
}
}