FieldElevationExtremumDetector.java

  1. /* Copyright 2022-2025 Luc Maisonobe
  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.propagation.events;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.ode.events.FieldEventSlopeFilter;
  23. import org.orekit.frames.FieldKinematicTransform;
  24. import org.orekit.frames.TopocentricFrame;
  25. import org.orekit.propagation.FieldSpacecraftState;
  26. import org.orekit.propagation.events.handlers.FieldEventHandler;
  27. import org.orekit.propagation.events.handlers.FieldStopOnIncreasing;
  28. import org.orekit.utils.TimeStampedFieldPVCoordinates;

  29. /** Detector for elevation extremum with respect to a ground point.
  30.  * <p>This detector identifies when a spacecraft reaches its
  31.  * extremum elevation with respect to a ground point.</p>
  32.  * <p>
  33.  * As in most cases only the elevation maximum is needed and the
  34.  * minimum is often irrelevant, this detector is often wrapped into
  35.  * an {@link FieldEventSlopeFilter event slope filter} configured with
  36.  * {@link FilterType#TRIGGER_ONLY_DECREASING_EVENTS} (i.e. when the
  37.  * elevation derivative decreases from positive values to negative values,
  38.  * which correspond to a maximum). Setting up this filter saves some computation
  39.  * time as the elevation minimum occurrences are not even looked at. It is
  40.  * however still often necessary to do an additional filtering
  41.  * </p>
  42.  * @param <T> type of the field element
  43.  * @author Luc Maisonobe
  44.  * @since 12.0
  45.  */
  46. public class FieldElevationExtremumDetector<T extends CalculusFieldElement<T>>
  47.     extends FieldAbstractDetector<FieldElevationExtremumDetector<T>, T> {

  48.     /** Topocentric frame in which elevation should be evaluated. */
  49.     private final TopocentricFrame topo;

  50.     /** Build a new detector.
  51.      * <p>The new instance uses default values for maximal checking interval
  52.      * ({@link #DEFAULT_MAX_CHECK}) and convergence threshold ({@link
  53.      * #DEFAULT_THRESHOLD}).</p>
  54.      * @param field field to which elements belong
  55.      * @param topo topocentric frame centered on ground point
  56.      */
  57.     public FieldElevationExtremumDetector(final Field<T> field, final TopocentricFrame topo) {
  58.         this(field.getZero().newInstance(DEFAULT_MAX_CHECK),
  59.              field.getZero().newInstance(DEFAULT_THRESHOLD),
  60.              topo);
  61.     }

  62.     /** Build a detector.
  63.      * @param maxCheck maximal checking interval (s)
  64.      * @param threshold convergence threshold (s)
  65.      * @param topo topocentric frame centered on ground point
  66.      */
  67.     public FieldElevationExtremumDetector(final T maxCheck, final T threshold,
  68.                                           final TopocentricFrame topo) {
  69.         this(new FieldEventDetectionSettings<>(maxCheck.getReal(), threshold, DEFAULT_MAX_ITER), new FieldStopOnIncreasing<>(),
  70.              topo);
  71.     }

  72.     /** Protected constructor with full parameters.
  73.      * <p>
  74.      * This constructor is not public as users are expected to use the builder
  75.      * API with the various {@code withXxx()} methods to set up the instance
  76.      * in a readable manner without using a huge amount of parameters.
  77.      * </p>
  78.      * @param detectionSettings event detection settings
  79.      * @param handler event handler to call at event occurrences
  80.      * @param topo topocentric frame centered on ground point
  81.      */
  82.     protected FieldElevationExtremumDetector(final FieldEventDetectionSettings<T> detectionSettings,
  83.                                              final FieldEventHandler<T> handler,
  84.                                              final TopocentricFrame topo) {
  85.         super(detectionSettings, handler);
  86.         this.topo = topo;
  87.     }

  88.     /** {@inheritDoc} */
  89.     @Override
  90.     protected FieldElevationExtremumDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
  91.                                                        final FieldEventHandler<T> newHandler) {
  92.         return new FieldElevationExtremumDetector<>(detectionSettings, newHandler, topo);
  93.     }

  94.     /**
  95.      * Returns the topocentric frame centered on ground point.
  96.      * @return topocentric frame centered on ground point
  97.      */
  98.     public TopocentricFrame getTopocentricFrame() {
  99.         return this.topo;
  100.     }

  101.     /** Get the elevation value.
  102.      * @param s the current state information: date, kinematics, attitude
  103.      * @return spacecraft elevation
  104.      */
  105.     public T getElevation(final FieldSpacecraftState<T> s) {
  106.         return topo.getElevation(s.getPosition(), s.getFrame(), s.getDate());
  107.     }

  108.     /** Compute the value of the detection function.
  109.      * <p>
  110.      * The value is the spacecraft elevation first time derivative.
  111.      * </p>
  112.      * @param s the current state information: date, kinematics, attitude
  113.      * @return spacecraft elevation first time derivative
  114.      */
  115.     public T g(final FieldSpacecraftState<T> s) {

  116.         // get position, velocity acceleration of spacecraft in topocentric frame
  117.         final FieldKinematicTransform<T> inertToTopo = s.getFrame().getKinematicTransformTo(topo, s.getDate());
  118.         final TimeStampedFieldPVCoordinates<T> pvTopo = inertToTopo.transformOnlyPV(s.getPVCoordinates());

  119.         // convert the coordinates to UnivariateDerivative1 based vector
  120.         // instead of having vector position, then vector velocity then vector acceleration
  121.         // we get one vector and each coordinate is a DerivativeStructure containing
  122.         // value, first time derivative (we don't need second time derivative here)
  123.         final FieldVector3D<FieldUnivariateDerivative1<T>> pvDS = pvTopo.toUnivariateDerivative1Vector();

  124.         // compute elevation and its first time derivative
  125.         final FieldUnivariateDerivative1<T> elevation = pvDS.getZ().divide(pvDS.getNorm()).asin();

  126.         // return elevation first time derivative
  127.         return elevation.getDerivative(1);

  128.     }

  129. }