MagneticFieldDetector.java

  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.propagation.events;

  18. import org.orekit.annotation.DefaultDataContext;
  19. import org.orekit.bodies.GeodeticPoint;
  20. import org.orekit.bodies.OneAxisEllipsoid;
  21. import org.orekit.data.DataContext;
  22. import org.orekit.models.earth.GeoMagneticField;
  23. import org.orekit.models.earth.GeoMagneticFieldFactory;
  24. import org.orekit.models.earth.GeoMagneticFieldFactory.FieldModel;
  25. import org.orekit.propagation.SpacecraftState;
  26. import org.orekit.propagation.events.handlers.EventHandler;
  27. import org.orekit.propagation.events.handlers.StopOnIncreasing;
  28. import org.orekit.time.AbsoluteDate;
  29. import org.orekit.time.TimeScale;

  30. /** Detector for Earth magnetic field strength.
  31.  * <p>
  32.  * The detector is based on the field intensity calculated at the
  33.  * satellite's latitude and longitude, either at sea level or at
  34.  * satellite altitude, depending on the value chosen for the
  35.  * <code>atSeaLevel</code> indicator.<br>
  36.  * It can detect flyovers of the South-Atlantic anomaly with
  37.  * a classically accepted limit value of 32,000 nT at sea level.
  38.  * </p>
  39.  * @author Romaric Her
  40.  */
  41. public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetector> {

  42.     /** Fixed threshold value of Magnetic field to be crossed, in Teslas. */
  43.     private final double limit;

  44.     /** Switch for calculating field strength at sea level (true) or satellite altitude (false). */
  45.     private final boolean atSeaLevel;

  46.     /** Earth geomagnetic field. */
  47.     private GeoMagneticField field;

  48.     /** year of the current state. */
  49.     private double currentYear;

  50.     /** Earth geomagnetic field model. */
  51.     private final FieldModel model;

  52.     /** Earth body shape. */
  53.     private final OneAxisEllipsoid body;

  54.     /** Current data context. */
  55.     private final DataContext dataContext;


  56.     /** Build a new detector.
  57.      *
  58.      * <p>This constructor uses:
  59.      * <ul>
  60.      * <li>the {@link DataContext#getDefault() default data context}</li>
  61.      * <li>the {@link AbstractDetector#DEFAULT_MAXCHECK default value} for maximal checking interval</li>
  62.      * <li>the {@link AbstractDetector#DEFAULT_THRESHOLD default value} for convergence threshold</li>
  63.      * <li>the <code>atSeaLevel</code> switch set to false</li>
  64.      * </ul>
  65.      *
  66.      * @param limit threshold value for magnetic field detection, in Teslas
  67.      * @param model magnetic field model
  68.      * @param body  Earth body shape
  69.      * @see #MagneticFieldDetector(double, double, double, GeoMagneticFieldFactory.FieldModel, OneAxisEllipsoid, boolean, DataContext)
  70.      */
  71.     @DefaultDataContext
  72.     public MagneticFieldDetector(final double limit, final FieldModel model, final OneAxisEllipsoid body) {
  73.         this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, limit, model, body, false);
  74.     }

  75.     /** Build a new detector.
  76.      *
  77.      * <p>This constructor uses:
  78.      * <ul>
  79.      * <li>the {@link DataContext#getDefault() default data context}</li>
  80.      * <li>the {@link AbstractDetector#DEFAULT_MAXCHECK default value} for maximal checking interval</li>
  81.      * <li>the {@link AbstractDetector#DEFAULT_THRESHOLD default value} for convergence threshold </li>
  82.      * </ul>
  83.      *
  84.      * @param limit    threshold value for magnetic field detection, in Teslas
  85.      * @param model    magnetic field model
  86.      * @param body     Earth body shape
  87.      * @param atSeaLevel switch for calculating field intensity at sea level (true) or satellite altitude (false)
  88.      * @see #MagneticFieldDetector(double, double, double, GeoMagneticFieldFactory.FieldModel, OneAxisEllipsoid, boolean, DataContext)
  89.      */
  90.     @DefaultDataContext
  91.     public MagneticFieldDetector(final double limit, final FieldModel model,
  92.                                  final OneAxisEllipsoid body, final boolean atSeaLevel) {
  93.         this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, limit, model, body, atSeaLevel);
  94.     }

  95.     /** Build a detector.
  96.      *
  97.      * <p>This method uses the {@link DataContext#getDefault() default data context}.</p>
  98.      *
  99.      * @param maxCheck   maximal checking interval (s)
  100.      * @param threshold  convergence threshold (s)
  101.      * @param limit      threshold value for magnetic field detection, in Teslas
  102.      * @param model      magnetic field model
  103.      * @param body       Earth body shape
  104.      * @param atSeaLevel switch for calculating field intensity at sea level (true) or satellite altitude (false)
  105.      * @see #MagneticFieldDetector(double, double, double, GeoMagneticFieldFactory.FieldModel, OneAxisEllipsoid, boolean, DataContext)
  106.      */
  107.     @DefaultDataContext
  108.     public MagneticFieldDetector(final double maxCheck, final double threshold, final double limit,
  109.                                  final FieldModel model, final OneAxisEllipsoid body, final boolean atSeaLevel) {
  110.         this(maxCheck, threshold, limit, model, body, atSeaLevel, DataContext.getDefault());
  111.     }

  112.     /**
  113.      * Build a detector.
  114.      *
  115.      * @param maxCheck    maximal checking interval (s)
  116.      * @param threshold   convergence threshold (s)
  117.      * @param limit       threshold value for magnetic field detection, in Teslas
  118.      * @param model       magnetic field model
  119.      * @param body        Earth body shape
  120.      * @param atSeaLevel  switch for calculating field intensity at sea level (true) or satellite altitude (false)
  121.      * @param dataContext used to look up the magnetic field model.
  122.      * @since 10.1
  123.      */
  124.     public MagneticFieldDetector(final double maxCheck,
  125.                                  final double threshold,
  126.                                  final double limit,
  127.                                  final FieldModel model,
  128.                                  final OneAxisEllipsoid body,
  129.                                  final boolean atSeaLevel,
  130.                                  final DataContext dataContext) {
  131.         this(AdaptableInterval.of(maxCheck), threshold, DEFAULT_MAX_ITER, new StopOnIncreasing(),
  132.              limit, model, body, atSeaLevel, dataContext);
  133.     }

  134.     /** Protected constructor with full parameters.
  135.      * <p>
  136.      * This constructor is not public as users are expected to use the builder
  137.      * API with the various {@code withXxx()} methods to set up the instance
  138.      * in a readable manner without using a huge amount of parameters.
  139.      * </p>
  140.      * @param maxCheck    maximal checking interval
  141.      * @param threshold   convergence threshold (s)
  142.      * @param maxIter     maximum number of iterations in the event time search
  143.      * @param handler     event handler to call at event occurrences
  144.      * @param limit       threshold value for magnetic field detection, in Teslas
  145.      * @param model       magnetic field model
  146.      * @param body        Earth body shape
  147.      * @param atSeaLevel  switch for calculating field intensity at sea level (true) or satellite altitude (false)
  148.      * @param dataContext used to look up the magnetic field model.
  149.      */
  150.     protected MagneticFieldDetector(final AdaptableInterval maxCheck, final double threshold,
  151.                                     final int maxIter, final EventHandler handler,
  152.                                     final double limit, final FieldModel model, final OneAxisEllipsoid body,
  153.                                     final boolean atSeaLevel, final DataContext dataContext) {
  154.         super(maxCheck, threshold, maxIter, handler);
  155.         this.limit       = limit;
  156.         this.model       = model;
  157.         this.body        = body;
  158.         this.atSeaLevel  = atSeaLevel;
  159.         this.dataContext = dataContext;
  160.     }

  161.     /** {@inheritDoc} */
  162.     @Override
  163.     protected MagneticFieldDetector create(final AdaptableInterval newMaxCheck, final double newThreshold,
  164.                                            final int newMaxIter, final EventHandler newHandler) {
  165.         return new MagneticFieldDetector(newMaxCheck, newThreshold, newMaxIter, newHandler,
  166.                                          limit, model, body, atSeaLevel, dataContext);
  167.     }

  168.     /** {@inheritDoc} */
  169.     public void init(final SpacecraftState s0, final AbsoluteDate t) {
  170.         super.init(s0, t);
  171.         final TimeScale utc = dataContext.getTimeScales().getUTC();
  172.         this.currentYear = s0.getDate().getComponents(utc).getDate().getYear();
  173.         this.field = dataContext.getGeoMagneticFields().getField(model, currentYear);
  174.     }

  175.     /** Compute the value of the detection function.
  176.      * <p>
  177.      * The returned value is the difference between the field intensity at spacecraft location,
  178.      * taking <code>atSeaLevel</code> switch into account, and the fixed threshold value.
  179.      * </p>
  180.      * @param s the current state information: date, kinematics, attitude
  181.      * @return difference between the field intensity at spacecraft location
  182.      *         and the fixed threshold value
  183.      */
  184.     public double g(final SpacecraftState s) {
  185.         final TimeScale utc = dataContext.getTimeScales().getUTC();
  186.         if (s.getDate().getComponents(utc).getDate().getYear() != currentYear) {
  187.             this.currentYear = s.getDate().getComponents(utc).getDate().getYear();
  188.             this.field = dataContext.getGeoMagneticFields().getField(model, currentYear);
  189.         }
  190.         final GeodeticPoint geoPoint = body.transform(s.getPosition(), s.getFrame(), s.getDate());
  191.         final double altitude = atSeaLevel ? 0. : geoPoint.getAltitude();
  192.         final double value = field.calculateField(geoPoint.getLatitude(), geoPoint.getLongitude(), altitude).getTotalIntensity();
  193.         return value - limit;
  194.     }

  195. }