JB2006.java

  1. /* Copyright 2002-2025 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.models.earth.atmosphere;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.util.FastMath;
  20. import org.hipparchus.util.FieldSinCos;
  21. import org.hipparchus.util.MathUtils;
  22. import org.orekit.annotation.DefaultDataContext;
  23. import org.orekit.bodies.BodyShape;
  24. import org.orekit.data.DataContext;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.time.TimeScale;
  27. import org.orekit.utils.ExtendedPositionProvider;

  28. /**
  29.  * This is the realization of the Jacchia-Bowman 2006 atmospheric model.
  30.  * <p>
  31.  * It is described in the paper: <br>
  32.  *
  33.  * <a href="http://sol.spacenvironment.net/~JB2006/pubs/JB2006_AIAA-6166_model.pdf">A
  34.  * New Empirical Thermospheric Density Model JB2006 Using New Solar Indices</a><br>
  35.  *
  36.  * <i>Bruce R. Bowman, W. Kent Tobiska and Frank A. Marcos</i> <br>
  37.  * <p>
  38.  * AIAA 2006-6166<br>
  39.  * </p>
  40.  *
  41.  * <p>
  42.  * This model provides dense output for all altitudes and positions. Output data are :
  43.  * <ul>
  44.  * <li>Exospheric Temperature above Input Position (deg K)</li>
  45.  * <li>Temperature at Input Position (deg K)</li>
  46.  * <li>Total Mass-Density at Input Position (kg/m³)</li>
  47.  * </ul>
  48.  *
  49.  * <p>
  50.  * The model needs geographical and time information to compute general values,
  51.  * but also needs space weather data : mean and daily solar flux, retrieved threw
  52.  * different indices, and planetary geomagnetic indices. <br>
  53.  * More information on these indices can be found on the  <a
  54.  * href="http://sol.spacenvironment.net/~JB2006/JB2006_index.html">
  55.  * official JB2006 website.</a>
  56.  * </p>
  57.  *
  58.  * @author Bruce R Bowman (HQ AFSPC, Space Analysis Division), Feb 2006: FORTRAN routine
  59.  * @author Fabien Maussion (java translation)
  60.  * @author Bryan Cazabonne (Orekit 13 update and field translation)
  61.  * @since 13.1
  62.  */
  63. public class JB2006 extends AbstractJacchiaBowmanModel {

  64.     /** FZ global model values (1978-2004 fit). */
  65.     private static final double[] FZM = { 0.111613e+00, -0.159000e-02, 0.126190e-01, -0.100064e-01, -0.237509e-04, 0.260759e-04};

  66.     /** GT global model values (1978-2004 fit). */
  67.     private static final double[] GTM = {-0.833646e+00, -0.265450e+00, 0.467603e+00, -0.299906e+00, -0.105451e+00,
  68.                                          -0.165537e-01, -0.380037e-01, -0.150991e-01, -0.541280e-01,  0.119554e-01,
  69.                                          0.437544e-02, -0.369016e-02, 0.206763e-02, -0.142888e-02, -0.867124e-05,
  70.                                          0.189032e-04, 0.156988e-03, 0.491286e-03, -0.391484e-04, -0.126854e-04,
  71.                                          0.134078e-04, -0.614176e-05, 0.343423e-05};

  72.     /** External data container. */
  73.     private final JB2006InputParameters inputParams;

  74.     /**
  75.      * Constructor with space environment information for internal computation.
  76.      *
  77.      * @param parameters the solar and magnetic activity data
  78.      * @param sun        the sun position
  79.      * @param earth      the earth body shape
  80.      */
  81.     @DefaultDataContext
  82.     public JB2006(final JB2006InputParameters parameters, final ExtendedPositionProvider sun, final BodyShape earth) {
  83.         this(parameters, sun, earth, DataContext.getDefault().getTimeScales().getUTC());
  84.     }

  85.     /**
  86.      * Constructor with space environment information for internal computation.
  87.      *
  88.      * @param parameters the solar and magnetic activity data
  89.      * @param sun        the sun position
  90.      * @param earth      the earth body shape
  91.      * @param utc        UTC time scale. Used to computed the day fraction.
  92.      */
  93.     public JB2006(final JB2006InputParameters parameters, final ExtendedPositionProvider sun,
  94.                   final BodyShape earth, final TimeScale utc) {
  95.         super(sun, utc, earth, parameters.getMinDate(), parameters.getMaxDate());
  96.         this.inputParams = parameters;
  97.     }

  98.     /** {@inheritDoc} */
  99.     @Override
  100.     protected double computeTInf(final AbsoluteDate date, final double tsubl, final double dtclst) {
  101.         return tsubl + getDtg(date) + dtclst;
  102.     }

  103.     /** {@inheritDoc} */
  104.     @Override
  105.     protected <T extends CalculusFieldElement<T>> T computeTInf(final AbsoluteDate date, final T tsubl, final T dtclst) {
  106.         return tsubl.add(getDtg(date)).add(dtclst);
  107.     }

  108.     /** {@inheritDoc} */
  109.     @Override
  110.     protected double computeTc(final AbsoluteDate date) {
  111.         final double f10   = inputParams.getF10(date);
  112.         final double f10B  = inputParams.getF10B(date);
  113.         final double s10   = inputParams.getS10(date);
  114.         final double s10B  = inputParams.getS10B(date);
  115.         final double xm10  = inputParams.getXM10(date);
  116.         final double xm10B = inputParams.getXM10B(date);
  117.         return 379 + 3.353 * f10B + 0.358 * (f10 - f10B) + 2.094 * (s10 - s10B) + 0.343 * (xm10 - xm10B);
  118.     }

  119.     /** {@inheritDoc} */
  120.     @Override
  121.     protected double getF10(final AbsoluteDate date) {
  122.         return inputParams.getF10(date);
  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     protected double getF10B(final AbsoluteDate date) {
  127.         return inputParams.getF10B(date);
  128.     }

  129.     /** {@inheritDoc} */
  130.     @Override
  131.     protected double semian(final AbsoluteDate date, final double day, final double height) {

  132.         final double f10Bar = inputParams.getF10B(date);
  133.         final double f10Bar2 = f10Bar * f10Bar;
  134.         final double htz = height / 1000.0;

  135.         // SEMIANNUAL AMPLITUDE
  136.         final double fzz = FZM[0] + FZM[1] * f10Bar + FZM[2] * f10Bar * htz + FZM[3] * f10Bar * htz * htz + FZM[4] * f10Bar * f10Bar * htz + FZM[5] * f10Bar * f10Bar * htz * htz;

  137.         // SEMIANNUAL PHASE FUNCTION
  138.         final double tau = MathUtils.TWO_PI * (day - 1.0) / 365;
  139.         final double sin1P = FastMath.sin(tau);
  140.         final double cos1P = FastMath.cos(tau);
  141.         final double sin2P = FastMath.sin(2.0 * tau);
  142.         final double cos2P = FastMath.cos(2.0 * tau);
  143.         final double sin3P = FastMath.sin(3.0 * tau);
  144.         final double cos3P = FastMath.cos(3.0 * tau);
  145.         final double sin4P = FastMath.sin(4.0 * tau);
  146.         final double cos4P = FastMath.cos(4.0 * tau);
  147.         final double gtz = GTM[0] +
  148.                            GTM[1] * sin1P +
  149.                            GTM[2] * cos1P +
  150.                            GTM[3] * sin2P +
  151.                            GTM[4] * cos2P +
  152.                            GTM[5] * sin3P +
  153.                            GTM[6] * cos3P +
  154.                            GTM[7] * sin4P +
  155.                            GTM[8] * cos4P +
  156.                            GTM[9] * f10Bar +
  157.                            GTM[10] * f10Bar * sin1P +
  158.                            GTM[11] * f10Bar * cos1P +
  159.                            GTM[12] * f10Bar * sin2P +
  160.                            GTM[13] * f10Bar * cos2P +
  161.                            GTM[14] * f10Bar * sin3P +
  162.                            GTM[15] * f10Bar * cos3P +
  163.                            GTM[16] * f10Bar * sin4P +
  164.                            GTM[17] * f10Bar * cos4P +
  165.                            GTM[18] * f10Bar2 +
  166.                            GTM[19] * f10Bar2 * sin1P +
  167.                            GTM[20] * f10Bar2 * cos1P +
  168.                            GTM[21] * f10Bar2 * sin2P +
  169.                            GTM[22] * f10Bar2 * cos2P;

  170.         return FastMath.max(1.0e-6, fzz) * gtz;
  171.     }
  172.     /** {@inheritDoc} */
  173.     @Override
  174.     protected <T extends CalculusFieldElement<T>> T semian(final AbsoluteDate date, final T doy, final T height) {

  175.         final double f10Bar = getF10B(date);
  176.         final double f10Bar2 = f10Bar * f10Bar;
  177.         final T htz = height.divide(1000.0);

  178.         // SEMIANNUAL AMPLITUDE
  179.         final T fzz = htz.multiply(FZM[2] * f10Bar).add(htz.square().multiply(FZM[3] * f10Bar)).add(htz.multiply(FZM[4] * f10Bar * f10Bar)).add(htz.square().multiply(FZM[5] * f10Bar * f10Bar)).add(FZM[0] + FZM[1] * f10Bar);

  180.         // SEMIANNUAL PHASE FUNCTION
  181.         final T tau   = doy.subtract(1).divide(365).multiply(MathUtils.TWO_PI);
  182.         final FieldSinCos<T> sc1P = FastMath.sinCos(tau);
  183.         final FieldSinCos<T> sc2P = FastMath.sinCos(tau.multiply(2.0));
  184.         final FieldSinCos<T> sc3P = FastMath.sinCos(tau.multiply(3.0));
  185.         final FieldSinCos<T> sc4P = FastMath.sinCos(tau.multiply(4.0));
  186.         final T gtz = sc1P.sin().multiply(GTM[1]).add(
  187.                       sc1P.cos().multiply(GTM[2])).add(
  188.                       sc2P.sin().multiply(GTM[3])).add(
  189.                       sc2P.cos().multiply(GTM[4])).add(
  190.                       sc3P.sin().multiply(GTM[5])).add(
  191.                       sc3P.cos().multiply(GTM[6])).add(
  192.                       sc4P.sin().multiply(GTM[7])).add(
  193.                       sc4P.cos().multiply(GTM[8])).add(
  194.                       GTM[9] * f10Bar).add(
  195.                       sc1P.sin().multiply(f10Bar).multiply(GTM[10])).add(
  196.                       sc1P.cos().multiply(f10Bar).multiply(GTM[11])).add(
  197.                       sc2P.sin().multiply(f10Bar).multiply(GTM[12])).add(
  198.                       sc2P.cos().multiply(f10Bar).multiply(GTM[13])).add(
  199.                       sc3P.sin().multiply(f10Bar).multiply(GTM[14])).add(
  200.                       sc3P.cos().multiply(f10Bar).multiply(GTM[15])).add(
  201.                       sc4P.sin().multiply(f10Bar).multiply(GTM[16])).add(
  202.                       sc4P.cos().multiply(f10Bar).multiply(GTM[17])).add(
  203.                       GTM[18] * f10Bar2).add(
  204.                       sc1P.sin().multiply(f10Bar2).multiply(GTM[19])).add(
  205.                       sc1P.cos().multiply(f10Bar2).multiply(GTM[20])).add(
  206.                       sc2P.sin().multiply(f10Bar2).multiply(GTM[21])).add(
  207.                       sc2P.cos().multiply(f10Bar2).multiply(GTM[22])).add(GTM[0]);

  208.         return fzz.getReal() > 1.0e-6 ? gtz.multiply(fzz) : gtz.multiply(1.0e-6);
  209.     }

  210.     /** Computes the temperature computed by Equation (18).
  211.      * @param date computation epoch
  212.      * @return the temperature given by Equation (18)
  213.      */
  214.     private double getDtg(final AbsoluteDate date) {
  215.         // Equation (18)
  216.         final double ap = inputParams.getAp(date);
  217.         final double expAp = FastMath.exp(-0.08 * ap);
  218.         return ap + 100. * (1. - expAp);
  219.     }
  220. }