FixedPointConverter.java
- /* Copyright 2002-2025 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.propagation.conversion.osc2mean;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.Field;
- import org.hipparchus.util.FastMath;
- import org.hipparchus.util.MathUtils;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.orbits.EquinoctialOrbit;
- import org.orekit.orbits.FieldEquinoctialOrbit;
- import org.orekit.orbits.FieldOrbit;
- import org.orekit.orbits.Orbit;
- import org.orekit.orbits.PositionAngleType;
- import org.orekit.time.FieldAbsoluteDate;
- /**
- * Class enabling conversion from osculating to mean orbit
- * for a given theory using a fixed-point algorithm.
- *
- * @author Pascal Parraud
- * @since 13.0
- */
- public class FixedPointConverter implements OsculatingToMeanConverter {
- /** Default convergence threshold. */
- public static final double DEFAULT_THRESHOLD = 1e-12;
- /** Default maximum number of iterations. */
- public static final int DEFAULT_MAX_ITERATIONS = 100;
- /** Default damping ratio. */
- public static final double DEFAULT_DAMPING = 1.;
- /** Mean theory used. */
- private MeanTheory theory;
- /** Convergence threshold. */
- private double threshold;
- /** Maximum number of iterations. */
- private int maxIterations;
- /** Damping ratio. */
- private double damping;
- /** Number of iterations performed. */
- private int iterationsNb;
- /**
- * Default constructor.
- * <p>
- * The mean theory must be set before converting.
- */
- public FixedPointConverter() {
- this(null, DEFAULT_THRESHOLD, DEFAULT_MAX_ITERATIONS, DEFAULT_DAMPING);
- }
- /**
- * Constructor.
- * @param theory mean theory to be used
- */
- public FixedPointConverter(final MeanTheory theory) {
- this(theory, DEFAULT_THRESHOLD, DEFAULT_MAX_ITERATIONS, DEFAULT_DAMPING);
- }
- /**
- * Constructor.
- * <p>
- * The mean theory must be set before converting.
- *
- * @param threshold tolerance for convergence
- * @param maxIterations maximum number of iterations
- * @param damping damping ratio
- */
- public FixedPointConverter(final double threshold,
- final int maxIterations,
- final double damping) {
- this(null, threshold, maxIterations, damping);
- }
- /**
- * Constructor.
- * @param theory mean theory to be used
- * @param threshold tolerance for convergence
- * @param maxIterations maximum number of iterations
- * @param damping damping ratio
- */
- public FixedPointConverter(final MeanTheory theory,
- final double threshold,
- final int maxIterations,
- final double damping) {
- setMeanTheory(theory);
- setThreshold(threshold);
- setMaxIterations(maxIterations);
- setDamping(damping);
- }
- /** {@inheritDoc} */
- @Override
- public MeanTheory getMeanTheory() {
- return theory;
- }
- /** {@inheritDoc} */
- @Override
- public void setMeanTheory(final MeanTheory meanTheory) {
- this.theory = meanTheory;
- }
- /**
- * Gets convergence threshold.
- * @return convergence threshold
- */
- public double getThreshold() {
- return threshold;
- }
- /**
- * Sets convergence threshold.
- * @param threshold convergence threshold
- */
- public void setThreshold(final double threshold) {
- this.threshold = threshold;
- }
- /**
- * Gets maximum number of iterations.
- * @return maximum number of iterations
- */
- public int getMaxIterations() {
- return maxIterations;
- }
- /**
- * Sets maximum number of iterations.
- * @param maxIterations maximum number of iterations
- */
- public void setMaxIterations(final int maxIterations) {
- this.maxIterations = maxIterations;
- }
- /**
- * Gets damping ratio.
- * @return damping ratio
- */
- public double getDamping() {
- return damping;
- }
- /**
- * Sets damping ratio.
- * @param damping damping ratio
- */
- public void setDamping(final double damping) {
- this.damping = damping;
- }
- /**
- * Gets the number of iterations performed by the last conversion.
- * @return number of iterations
- */
- public int getIterationsNb() {
- return iterationsNb;
- }
- /** {@inheritDoc}
- * Uses a fixed-point algorithm.
- */
- @Override
- public Orbit convertToMean(final Orbit osculating) {
- // sanity check
- if (osculating.getA() < theory.getReferenceRadius()) {
- throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE,
- osculating.getA());
- }
- // Get equinoctial osculating parameters
- final Orbit equinoctial = theory.preprocessing(osculating);
- double sma = equinoctial.getA();
- double ex = equinoctial.getEquinoctialEx();
- double ey = equinoctial.getEquinoctialEy();
- double hx = equinoctial.getHx();
- double hy = equinoctial.getHy();
- double lv = equinoctial.getLv();
- // Set threshold for each parameter
- final double thresholdA = threshold * FastMath.abs(sma);
- final double thresholdE = threshold * (1 + FastMath.hypot(ex, ey));
- final double thresholdH = threshold * (1 + FastMath.hypot(hx, hy));
- final double thresholdLv = threshold * FastMath.PI;
- // Rough initialization of the mean parameters
- Orbit mean = theory.initialize(equinoctial);
- int i = 0;
- while (i++ < maxIterations) {
- // Update osculating parameters from current mean parameters
- final Orbit updated = theory.meanToOsculating(mean);
- // Updated parameters residuals
- final double deltaA = equinoctial.getA() - updated.getA();
- final double deltaEx = equinoctial.getEquinoctialEx() - updated.getEquinoctialEx();
- final double deltaEy = equinoctial.getEquinoctialEy() - updated.getEquinoctialEy();
- final double deltaHx = equinoctial.getHx() - updated.getHx();
- final double deltaHy = equinoctial.getHy() - updated.getHy();
- final double deltaLv = MathUtils.normalizeAngle(equinoctial.getLv() - updated.getLv(), 0.0);
- // Check convergence
- if (FastMath.abs(deltaA) < thresholdA &&
- FastMath.abs(deltaEx) < thresholdE &&
- FastMath.abs(deltaEy) < thresholdE &&
- FastMath.abs(deltaHx) < thresholdH &&
- FastMath.abs(deltaHy) < thresholdH &&
- FastMath.abs(deltaLv) < thresholdLv) {
- // Records number of iterations performed
- iterationsNb = i;
- // Returns the mean orbit
- return theory.postprocessing(osculating, mean);
- }
- // Update mean parameters
- sma += damping * deltaA;
- ex += damping * deltaEx;
- ey += damping * deltaEy;
- hx += damping * deltaHx;
- hy += damping * deltaHy;
- lv += damping * deltaLv;
- // Update mean orbit
- mean = new EquinoctialOrbit(sma, ex, ey, hx, hy, lv,
- PositionAngleType.TRUE,
- equinoctial.getFrame(),
- equinoctial.getDate(),
- equinoctial.getMu());
- }
- throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_MEAN_PARAMETERS, theory.getTheoryName(), i);
- }
- /** {@inheritDoc}
- * Uses a fixed-point algorithm.
- */
- @Override
- public <T extends CalculusFieldElement<T>> FieldOrbit<T> convertToMean(final FieldOrbit<T> osculating) {
- // Sanity check
- if (osculating.getA().getReal() < theory.getReferenceRadius()) {
- throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE,
- osculating.getA());
- }
- // Get field
- final FieldAbsoluteDate<T> date = osculating.getDate();
- final Field<T> field = date.getField();
- final T zero = field.getZero();
- final T pi = zero.getPi();
- // Get equinoctial parameters
- final FieldOrbit<T> equinoctial = theory.preprocessing(osculating);
- T sma = equinoctial.getA();
- T ex = equinoctial.getEquinoctialEx();
- T ey = equinoctial.getEquinoctialEy();
- T hx = equinoctial.getHx();
- T hy = equinoctial.getHy();
- T lv = equinoctial.getLv();
- // Set threshold for each parameter
- final T thresholdA = sma.abs().multiply(threshold);
- final T thresholdE = FastMath.hypot(ex, ey).add(1).multiply(threshold);
- final T thresholdH = FastMath.hypot(hx, hy).add(1).multiply(threshold);
- final T thresholdLv = pi.multiply(threshold);
- // Rough initialization of the mean parameters
- FieldOrbit<T> mean = theory.initialize(equinoctial);
- int i = 0;
- while (i++ < maxIterations) {
- // recompute the osculating parameters from the current mean parameters
- final FieldOrbit<T> updated = theory.meanToOsculating(mean);
- // Updated parameters residuals
- final T deltaA = equinoctial.getA().subtract(updated.getA());
- final T deltaEx = equinoctial.getEquinoctialEx().subtract(updated.getEquinoctialEx());
- final T deltaEy = equinoctial.getEquinoctialEy().subtract(updated.getEquinoctialEy());
- final T deltaHx = equinoctial.getHx().subtract(updated.getHx());
- final T deltaHy = equinoctial.getHy().subtract(updated.getHy());
- final T deltaLv = MathUtils.normalizeAngle(equinoctial.getLv().subtract(updated.getLv()), zero);
- // Check convergence
- if (FastMath.abs(deltaA.getReal()) < thresholdA.getReal() &&
- FastMath.abs(deltaEx.getReal()) < thresholdE.getReal() &&
- FastMath.abs(deltaEy.getReal()) < thresholdE.getReal() &&
- FastMath.abs(deltaHx.getReal()) < thresholdH.getReal() &&
- FastMath.abs(deltaHy.getReal()) < thresholdH.getReal() &&
- FastMath.abs(deltaLv.getReal()) < thresholdLv.getReal()) {
- // Records number of iterations performed
- iterationsNb = i;
- // Returns the mean orbit
- return theory.postprocessing(osculating, mean);
- }
- // Update mean parameters
- sma = sma.add(deltaA.multiply(damping));
- ex = ex.add(deltaEx.multiply(damping));
- ey = ey.add(deltaEy.multiply(damping));
- hx = hx.add(deltaHx.multiply(damping));
- hy = hy.add(deltaHy.multiply(damping));
- lv = lv.add(deltaLv.multiply(damping));
- // Update mean orbit
- mean = new FieldEquinoctialOrbit<>(sma, ex, ey, hx, hy, lv,
- PositionAngleType.TRUE,
- equinoctial.getFrame(),
- equinoctial.getDate(),
- equinoctial.getMu());
- }
- throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_MEAN_PARAMETERS, theory.getTheoryName(), i);
- }
- }