CylindricallyShadowedLightFluxModel.java

  1. /* Copyright 2022-2025 Romain Serra
  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.radiation;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  21. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  22. import org.orekit.propagation.events.CylindricalShadowEclipseDetector;
  23. import org.orekit.propagation.events.EventDetector;
  24. import org.orekit.propagation.events.EventDetectionSettings;
  25. import org.orekit.propagation.events.FieldCylindricalShadowEclipseDetector;
  26. import org.orekit.propagation.events.FieldEventDetector;
  27. import org.orekit.propagation.events.FieldEventDetectionSettings;
  28. import org.orekit.propagation.events.handlers.FieldResetDerivativesOnEvent;
  29. import org.orekit.propagation.events.handlers.ResetDerivativesOnEvent;
  30. import org.orekit.utils.ExtendedPositionProvider;

  31. import java.util.ArrayList;
  32. import java.util.List;

  33. /**
  34.  * Class defining a flux model with a single occulting body, casting a shadow whose shape is a circular cylinder
  35.  * (equivalent to the light source being infinitely distant). It is less accurate but faster to evaluate than a conical
  36.  * model.
  37.  *
  38.  * @author Romain Serra
  39.  * @see AbstractSolarLightFluxModel
  40.  * @see LightFluxModel
  41.  * @since 12.1
  42.  */
  43. public class CylindricallyShadowedLightFluxModel extends AbstractSolarLightFluxModel {

  44.     /**
  45.      * Default max. check interval for eclipse detection.
  46.      */
  47.     private static final double CYLINDRICAL_ECLIPSE_MAX_CHECK = 100;

  48.     /**
  49.      * Default threshold for eclipse detection.
  50.      */
  51.     private static final double CYLINDRICAL_ECLIPSE_THRESHOLD = 1e-7;

  52.     /**
  53.      * Constructor.
  54.      * @param kRef reference flux
  55.      * @param occultedBody position provider for light source
  56.      * @param occultingBodyRadius radius of central, occulting body
  57.      * @param eventDetectionSettings user-defined detection settings for eclipses (if ill-tuned, events might be missed or performance might drop)
  58.      * @since 12.2
  59.      */
  60.     public CylindricallyShadowedLightFluxModel(final double kRef, final ExtendedPositionProvider occultedBody,
  61.                                                final double occultingBodyRadius, final EventDetectionSettings eventDetectionSettings) {
  62.         super(kRef, occultedBody, occultingBodyRadius, eventDetectionSettings);
  63.     }

  64.     /**
  65.      * Constructor with default event detection settings.
  66.      * @param kRef reference flux
  67.      * @param occultedBody position provider for light source
  68.      * @param occultingBodyRadius radius of central, occulting body
  69.      */
  70.     public CylindricallyShadowedLightFluxModel(final double kRef, final ExtendedPositionProvider occultedBody,
  71.                                                final double occultingBodyRadius) {
  72.         this(kRef, occultedBody, occultingBodyRadius, getDefaultEclipseDetectionSettings());
  73.     }

  74.     /**
  75.      * Constructor with default value for reference flux.
  76.      * @param occultedBody position provider for light source
  77.      * @param occultingBodyRadius radius of central, occulting body
  78.      */
  79.     public CylindricallyShadowedLightFluxModel(final ExtendedPositionProvider occultedBody,
  80.                                                final double occultingBodyRadius) {
  81.         super(occultedBody, occultingBodyRadius, getDefaultEclipseDetectionSettings());
  82.     }

  83.     /**
  84.      * Define default detection settings for eclipses.
  85.      * @return default settings
  86.      * @since 12.2
  87.      */
  88.     public static EventDetectionSettings getDefaultEclipseDetectionSettings() {
  89.         return new EventDetectionSettings(CYLINDRICAL_ECLIPSE_MAX_CHECK, CYLINDRICAL_ECLIPSE_THRESHOLD,
  90.                 EventDetectionSettings.DEFAULT_MAX_ITER);
  91.     }

  92.     /** {@inheritDoc} */
  93.     @Override
  94.     protected double getLightingRatio(final Vector3D position, final Vector3D occultedBodyPosition) {
  95.         final Vector3D occultedBodyDirection = occultedBodyPosition.normalize();
  96.         final double dotProduct = position.dotProduct(occultedBodyDirection);
  97.         if (dotProduct < 0.) {
  98.             final double distanceToCylinderAxis = (position.subtract(occultedBodyDirection.scalarMultiply(dotProduct))).getNorm();
  99.             if (distanceToCylinderAxis <= getOccultingBodyRadius()) {
  100.                 return 0.;
  101.             }
  102.         }
  103.         return 1.;
  104.     }

  105.     /** {@inheritDoc} */
  106.     @Override
  107.     protected <T extends CalculusFieldElement<T>> T getLightingRatio(final FieldVector3D<T> position,
  108.                                                                      final FieldVector3D<T> occultedBodyPosition) {
  109.         final Field<T> field = position.getX().getField();
  110.         final FieldVector3D<T> occultedBodyDirection = occultedBodyPosition.normalize();
  111.         final T dotProduct = position.dotProduct(occultedBodyDirection);
  112.         if (dotProduct.getReal() < 0.) {
  113.             final T distanceToCylinderAxis = (position.subtract(occultedBodyDirection.scalarMultiply(dotProduct))).getNorm();
  114.             if (distanceToCylinderAxis.getReal() <= getOccultingBodyRadius()) {
  115.                 return field.getZero();
  116.             }
  117.         }
  118.         return field.getOne();
  119.     }


  120.     /** {@inheritDoc} */
  121.     @Override
  122.     public List<EventDetector> getEclipseConditionsDetector() {
  123.         final List<EventDetector> detectors = new ArrayList<>();
  124.         detectors.add(createCylindricalShadowEclipseDetector().withDetectionSettings(getEventDetectionSettings()));
  125.         return detectors;
  126.     }

  127.     /**
  128.      * Method to create a new eclipse detector.
  129.      * @return detector
  130.      */
  131.     private CylindricalShadowEclipseDetector createCylindricalShadowEclipseDetector() {
  132.         return new CylindricalShadowEclipseDetector(getOccultedBody(), getOccultingBodyRadius(),
  133.                 new ResetDerivativesOnEvent());
  134.     }

  135.     /** {@inheritDoc} */
  136.     @Override
  137.     public <T extends CalculusFieldElement<T>> List<FieldEventDetector<T>> getFieldEclipseConditionsDetector(final Field<T> field) {
  138.         final List<FieldEventDetector<T>> detectors = new ArrayList<>();
  139.         final FieldEventDetectionSettings<T> detectionSettings = new FieldEventDetectionSettings<>(field, getEventDetectionSettings());
  140.         detectors.add(createFieldCylindricalShadowEclipseDetector(field).withDetectionSettings(detectionSettings));
  141.         return detectors;
  142.     }

  143.     /**
  144.      * Method to create a new eclipse detector. Field version.
  145.      * @param field field
  146.      * @param <T> field type
  147.      * @return detector
  148.      */
  149.     private <T extends CalculusFieldElement<T>> FieldCylindricalShadowEclipseDetector<T> createFieldCylindricalShadowEclipseDetector(final Field<T> field) {
  150.         final T occultingBodyRadiusAsField = field.getZero().newInstance(getOccultingBodyRadius());
  151.         return new FieldCylindricalShadowEclipseDetector<>(getOccultedBody(), occultingBodyRadiusAsField,
  152.                 new FieldResetDerivativesOnEvent<>());
  153.     }
  154. }