NRLMSISE00.java

  1. /* Copyright 2002-2018 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.drag.atmosphere;

  18. import java.util.Arrays;

  19. import org.hipparchus.Field;
  20. import org.hipparchus.RealFieldElement;
  21. import org.hipparchus.exception.LocalizedCoreFormats;
  22. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  23. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  24. import org.hipparchus.util.FastMath;
  25. import org.hipparchus.util.MathArrays;
  26. import org.orekit.bodies.BodyShape;
  27. import org.orekit.bodies.FieldGeodeticPoint;
  28. import org.orekit.bodies.GeodeticPoint;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.OrekitMessages;
  31. import org.orekit.frames.Frame;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.time.DateTimeComponents;
  34. import org.orekit.time.FieldAbsoluteDate;
  35. import org.orekit.time.TimeComponents;
  36. import org.orekit.time.TimeScale;
  37. import org.orekit.time.TimeScalesFactory;
  38. import org.orekit.utils.IERSConventions;
  39. import org.orekit.utils.PVCoordinatesProvider;


  40. /** This class implements the mathematical representation of the 2001
  41.  *  Naval Research Laboratory Mass Spectrometer and Incoherent Scatter
  42.  *  Radar Exosphere (NRLMSISE-00) of the MSIS® class model.
  43.  *  <p>
  44.  *  NRLMSISE-00 calculates the neutral atmosphere empirical model from the surface
  45.  *  to lower exosphere (0 to 1000 km) and provides:
  46.  *  <ul>
  47.  *  <li>Exospheric Temperature above Input Position (K)</li>
  48.  *  <li>Local Temperature at Input Position (K)</li>
  49.  *  <li>Total Mass-Density at Input Position (kg/m³)</li>
  50.  *  <li>Partial Densities at Input Position (1/m³) for:
  51.  *  <ul>
  52.  *      <li>He,</li>
  53.  *      <li>H,</li>
  54.  *      <li>N,</li>
  55.  *      <li>O,</li>
  56.  *      <li>Ar,</li>
  57.  *      <li>N2,</li>
  58.  *      <li>O2,</li>
  59.  *      <li>anomalous oxygen.</li>
  60.  *  </ul>
  61.  *  </li>
  62.  *  </ul>
  63.  *  </p>
  64.  *  <p>
  65.  *  The model needs geographical and time information to compute general values,
  66.  *  but also needs space weather data:
  67.  *  <ul>
  68.  *  <li>mean and daily solar flux,</li>
  69.  *  <li>geomagnetic indices.</li>
  70.  *  </ul>
  71.  *  </p>
  72.  *  <p>
  73.  *  Switches can be used to turn on and off particular variations:<br>
  74.  *  0 is off, 1 is on, and 2 is main effects off but cross terms on.<br>
  75.  *  The standard value is 1 for all the 23 available switches.<br>
  76.  *  Function of each switch according to its number:
  77.  *  <ul>
  78.  *  <li>#1 - F10.7 effect on mean</li>
  79.  *  <li>#2 - Independent of time</li>
  80.  *  <li>#3 - Symmetrical annual</li>
  81.  *  <li>#4 - Symmetrical semiannual</li>
  82.  *  <li>#5 - Asymmetrical annual</li>
  83.  *  <li>#6 - Asymmetrical semiannual</li>
  84.  *  <li>#7 - Diurnal</li>
  85.  *  <li>#8 - Semidiurnal</li>
  86.  *  <li>#9 - Daily Ap [**]</li>
  87.  *  <li>#10 - All UT, longitudinal effects</li>
  88.  *  <li>#11 - Longitudinal</li>
  89.  *  <li>#12 - UT and mixed UT, longitudinal</li>
  90.  *  <li>#13 - Mixed AP, UT, longitudinal</li>
  91.  *  <li>#14 - Terdiurnal</li>
  92.  *  <li>#15 - Departures from diffusive equilibrium</li>
  93.  *  <li>#16 - All exospheric temperature variations</li>
  94.  *  <li>#17 - All variations from 120 km temperature (TLB)</li>
  95.  *  <li>#18 - All lower thermosphere (TN1) temperature variations</li>
  96.  *  <li>#19 - All 120 km gradient (S) variations</li>
  97.  *  <li>#20 - All upper stratosphere (TN2) temperature variations</li>
  98.  *  <li>#21 - All variations from 120 km values (ZLB)</li>
  99.  *  <li>#22 - All lower mesosphere temperature (TN3) variations</li>
  100.  *  <li>#23 - Turbopause scale height variations</li>
  101.  *  </ul>
  102.  *  [**] Switch #9 is a bit specific:
  103.  *  <ul>
  104.  *  <li>set to  1, the daily Ap only is used (first element of ap array),</li>
  105.  *  <li>set to -1, the entire array of ap is used, including 3 hr ap indices.</li>
  106.  *  </ul>
  107.  *  </p>
  108.  *  <p>
  109.  *  The NRLMSISE-00 model was developed by Mike Picone, Alan Hedin, and Doug Drob.<br>
  110.  *  They also wrote a NRLMSISE-00 distribution package in FORTRAN available at:<br>
  111.  *  ftp://hanna.ccmc.gsfc.nasa.gov/pub/modelweb/atmospheric/msis/nrlmsise00/<br>
  112.  *  <br>
  113.  *  Dominik Brodowski implemented a C version of the NRLMSISE-00 model available at:<br>
  114.  *  http://www.brodo.de/space/nrlmsise/index.html
  115.  *  </p>
  116.  *  <p>
  117.  *  Instances of this class are immutable.
  118.  *  </p>
  119.  *
  120.  *  @author Mike Picone & al (Naval Research Laboratory), 2001: FORTRAN routine
  121.  *  @author Dominik Brodowski, 2004: C routine
  122.  *  @author Pascal Parraud, 2016: Java translation
  123.  *  @since 8.1
  124.  */
  125. public class NRLMSISE00 implements Atmosphere {

  126.     /** Serializable UID. */
  127.     private static final long serialVersionUID = -7923498628122574334L;

  128.     // Constants

  129.     /** Identifier for helium density. */
  130.     private static final int HELIUM = 0;

  131.     /** Identifier for atomic oxygen density. */
  132.     private static final int ATOMIC_OXYGEN = 1;

  133.     /** Identifier for molecular nitrogen density. */
  134.     private static final int MOLECULAR_NITROGEN = 2;

  135.     /** Identifier for molecular oxygen density. */
  136.     private static final int MOLECULAR_OXYGEN = 3;

  137.     /** Identifier for argon density. */
  138.     private static final int ARGON = 4;

  139.     /** Identifier for atomic nitrogen density. */
  140.     private static final int TOTAL_MASS = 5;

  141.     /** Identifier for hydrogen density. */
  142.     private static final int HYDROGEN = 6;

  143.     /** Identifier for atomic nitrogen density. */
  144.     private static final int ATOMIC_NITROGEN = 7;

  145.     /** Identifier for anomalous oxygen density. */
  146.     private static final int ANOMALOUS_OXYGEN = 8;

  147.     /** Identifier for exospheric temperature. */
  148.     private static final int EXOSPHERIC = 0;

  149.     /** Identifier for temperature at altitude. */
  150.     private static final int ALTITUDE = 1;

  151.     // CONVERSION CONSTANTS

  152.     /** Conversion from degree to radian. */
  153.     private static final double DEG_TO_RAD = 1.74533e-2;

  154.     /** Conversion from day to radian. */
  155.     private static final double DAY_TO_RAD = 1.72142e-2;

  156.     /** Conversion from hour to radian. */
  157.     private static final double HOUR_TO_RAD = 0.2618;

  158.     /** Conversion from second to radian. */
  159.     private static final double SEC_TO_RAD = 7.2722e-5;

  160.     // EARTH GEOPHYSICAL CONSTANTS

  161.     /** Reference latitude (°). */
  162.     private static final double LAT_REF = 45.;

  163.     /** Reference gravity on Earth surface at reference latitude (cm/s2). */
  164.     private static final double G_REF = 980.616;

  165.     // CHEMICAL CONSTANTS

  166.     /** Unified atomic mass unit (kg). */
  167.     private static final double AMU = 1.66e-27;

  168.     /** Gas constant (inverse of). */
  169.     private static final double R_GAS = 831.4;

  170.     /** Hydrogen atomic mass. */
  171.     private static final double H_MASS = 1.;

  172.     /** Helium atomic mass. */
  173.     private static final double HE_MASS = 4.;

  174.     /** Nitrogen atomic mass. */
  175.     private static final double N_MASS = 14.;

  176.     /** N2 molecular mass. */
  177.     private static final double N2_MASS = 2. * N_MASS;

  178.     /** Oxygen atomic mass. */
  179.     private static final double O_MASS = 16.;

  180.     /** O2 molecular mass. */
  181.     private static final double O2_MASS = 2. * O_MASS;

  182.     /** Argon atomic mass. */
  183.     private static final double AR_MASS = 40.;

  184.     // NRL MSISE 2000 SPECIFIC CONSTANTS

  185.     /** Reference average flux. */
  186.     private static final double FLUX_REF = 150.;

  187.     /** Array of altitudes #1. */
  188.     private static final double[] ZN1 = {123.435, 110.0, 100.0, 90.0, 72.5};

  189.     /** Array of altitudes #2. */
  190.     private static final double[] ZN2 = {72.5, 55.0, 45.0, 32.5};

  191.     /** Array of altitudes #3. */
  192.     private static final double[] ZN3 = {32.5, 20.0, 15.0, 10.0, 0.0};

  193.     /** Mix altitude (km). */
  194.     private static final double ZMIX = 62.5;

  195.     /** NRLMSISE-00 data: temperature pt[150]. */
  196.     private static final double[] PT = {
  197.         9.86573e-01, 1.62228e-02, 1.55270e-02, -1.04323e-01, -3.75801e-03,
  198.         -1.18538e-03, -1.24043e-01, 4.56820e-03, 8.76018e-03, -1.36235e-01,
  199.         -3.52427e-02, 8.84181e-03, -5.92127e-03, -8.61650e+00, 0.00000e+00,
  200.         1.28492e-02, 0.00000e+00, 1.30096e+02, 1.04567e-02, 1.65686e-03,
  201.         -5.53887e-06, 2.97810e-03, 0.00000e+00, 5.13122e-03, 8.66784e-02,
  202.         1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, -7.27026e-06,
  203.         0.00000e+00, 6.74494e+00, 4.93933e-03, 2.21656e-03, 2.50802e-03,
  204.         0.00000e+00, 0.00000e+00, -2.08841e-02, -1.79873e+00, 1.45103e-03,
  205.         2.81769e-04, -1.44703e-03, -5.16394e-05, 8.47001e-02, 1.70147e-01,
  206.         5.72562e-03, 5.07493e-05, 4.36148e-03, 1.17863e-04, 4.74364e-03,
  207.         6.61278e-03, 4.34292e-05, 1.44373e-03, 2.41470e-05, 2.84426e-03,
  208.         8.56560e-04, 2.04028e-03, 0.00000e+00, -3.15994e+03, -2.46423e-03,
  209.         1.13843e-03, 4.20512e-04, 0.00000e+00, -9.77214e+01, 6.77794e-03,
  210.         5.27499e-03, 1.14936e-03, 0.00000e+00, -6.61311e-03, -1.84255e-02,
  211.         -1.96259e-02, 2.98618e+04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  212.         6.44574e+02, 8.84668e-04, 5.05066e-04, 0.00000e+00, 4.02881e+03,
  213.         -1.89503e-03, 0.00000e+00, 0.00000e+00, 8.21407e-04, 2.06780e-03,
  214.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  215.         -1.20410e-02, -3.63963e-03, 9.92070e-05, -1.15284e-04, -6.33059e-05,
  216.         -6.05545e-01, 8.34218e-03, -9.13036e+01, 3.71042e-04, 0.00000e+00,
  217.         4.19000e-04, 2.70928e-03, 3.31507e-03, -4.44508e-03, -4.96334e-03,
  218.         -1.60449e-03, 3.95119e-03, 2.48924e-03, 5.09815e-04, 4.05302e-03,
  219.         2.24076e-03, 0.00000e+00, 6.84256e-03, 4.66354e-04, 0.00000e+00,
  220.         -3.68328e-04, 0.00000e+00, 0.00000e+00, -1.46870e+02, 0.00000e+00,
  221.         0.00000e+00, 1.09501e-03, 4.65156e-04, 5.62583e-04, 3.21596e+00,
  222.         6.43168e-04, 3.14860e-03, 3.40738e-03, 1.78481e-03, 9.62532e-04,
  223.         5.58171e-04, 3.43731e+00, -2.33195e-01, 5.10289e-04, 0.00000e+00,
  224.         0.00000e+00, -9.25347e+04, 0.00000e+00, -1.99639e-03, 0.00000e+00,
  225.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  226.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  227.     };

  228.     /** NRLMSISE-00 data: density pd[9][150]. */
  229.     private static final double[][] PD = {
  230.         // HE DENSITY
  231.         {
  232.             1.09979e+00, -4.88060e-02, -1.97501e-01, -9.10280e-02, -6.96558e-03,
  233.             2.42136e-02, 3.91333e-01, -7.20068e-03, -3.22718e-02, 1.41508e+00,
  234.             1.68194e-01, 1.85282e-02, 1.09384e-01, -7.24282e+00, 0.00000e+00,
  235.             2.96377e-01, -4.97210e-02, 1.04114e+02, -8.61108e-02, -7.29177e-04,
  236.             1.48998e-06, 1.08629e-03, 0.00000e+00, 0.00000e+00, 8.31090e-02,
  237.             1.12818e-01, -5.75005e-02, -1.29919e-02, -1.78849e-02, -2.86343e-06,
  238.             0.00000e+00, -1.51187e+02, -6.65902e-03, 0.00000e+00, -2.02069e-03,
  239.             0.00000e+00, 0.00000e+00, 4.32264e-02, -2.80444e+01, -3.26789e-03,
  240.             2.47461e-03, 0.00000e+00, 0.00000e+00, 9.82100e-02, 1.22714e-01,
  241.             -3.96450e-02, 0.00000e+00, -2.76489e-03, 0.00000e+00, 1.87723e-03,
  242.             -8.09813e-03, 4.34428e-05, -7.70932e-03, 0.00000e+00, -2.28894e-03,
  243.             -5.69070e-03, -5.22193e-03, 6.00692e-03, -7.80434e+03, -3.48336e-03,
  244.             -6.38362e-03, -1.82190e-03, 0.00000e+00, -7.58976e+01, -2.17875e-02,
  245.             -1.72524e-02, -9.06287e-03, 0.00000e+00, 2.44725e-02, 8.66040e-02,
  246.             1.05712e-01, 3.02543e+04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  247.             -6.01364e+03, -5.64668e-03, -2.54157e-03, 0.00000e+00, 3.15611e+02,
  248.             -5.69158e-03, 0.00000e+00, 0.00000e+00, -4.47216e-03, -4.49523e-03,
  249.             4.64428e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  250.             4.51236e-02, 2.46520e-02, 6.17794e-03, 0.00000e+00, 0.00000e+00,
  251.             -3.62944e-01, -4.80022e-02, -7.57230e+01, -1.99656e-03, 0.00000e+00,
  252.             -5.18780e-03, -1.73990e-02, -9.03485e-03, 7.48465e-03, 1.53267e-02,
  253.             1.06296e-02, 1.18655e-02, 2.55569e-03, 1.69020e-03, 3.51936e-02,
  254.             -1.81242e-02, 0.00000e+00, -1.00529e-01, -5.10574e-03, 0.00000e+00,
  255.             2.10228e-03, 0.00000e+00, 0.00000e+00, -1.73255e+02, 5.07833e-01,
  256.             -2.41408e-01, 8.75414e-03, 2.77527e-03, -8.90353e-05, -5.25148e+00,
  257.             -5.83899e-03, -2.09122e-02, -9.63530e-03, 9.77164e-03, 4.07051e-03,
  258.             2.53555e-04, -5.52875e+00, -3.55993e-01, -2.49231e-03, 0.00000e+00,
  259.             0.00000e+00, 2.86026e+01, 0.00000e+00, 3.42722e-04, 0.00000e+00,
  260.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  261.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  262.         },
  263.         // O DENSITY
  264.         {
  265.             1.02315e+00, -1.59710e-01, -1.06630e-01, -1.77074e-02, -4.42726e-03,
  266.             3.44803e-02, 4.45613e-02, -3.33751e-02, -5.73598e-02, 3.50360e-01,
  267.             6.33053e-02, 2.16221e-02, 5.42577e-02, -5.74193e+00, 0.00000e+00,
  268.             1.90891e-01, -1.39194e-02, 1.01102e+02, 8.16363e-02, 1.33717e-04,
  269.             6.54403e-06, 3.10295e-03, 0.00000e+00, 0.00000e+00, 5.38205e-02,
  270.             1.23910e-01, -1.39831e-02, 0.00000e+00, 0.00000e+00, -3.95915e-06,
  271.             0.00000e+00, -7.14651e-01, -5.01027e-03, 0.00000e+00, -3.24756e-03,
  272.             0.00000e+00, 0.00000e+00, 4.42173e-02, -1.31598e+01, -3.15626e-03,
  273.             1.24574e-03, -1.47626e-03, -1.55461e-03, 6.40682e-02, 1.34898e-01,
  274.             -2.42415e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 6.13666e-04,
  275.             -5.40373e-03, 2.61635e-05, -3.33012e-03, 0.00000e+00, -3.08101e-03,
  276.             -2.42679e-03, -3.36086e-03, 0.00000e+00, -1.18979e+03, -5.04738e-02,
  277.             -2.61547e-03, -1.03132e-03, 1.91583e-04, -8.38132e+01, -1.40517e-02,
  278.             -1.14167e-02, -4.08012e-03, 1.73522e-04, -1.39644e-02, -6.64128e-02,
  279.             -6.85152e-02, -1.34414e+04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  280.             6.07916e+02, -4.12220e-03, -2.20996e-03, 0.00000e+00, 1.70277e+03,
  281.             -4.63015e-03, 0.00000e+00, 0.00000e+00, -2.25360e-03, -2.96204e-03,
  282.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  283.             3.92786e-02, 1.31186e-02, -1.78086e-03, 0.00000e+00, 0.00000e+00,
  284.             -3.90083e-01, -2.84741e-02, -7.78400e+01, -1.02601e-03, 0.00000e+00,
  285.             -7.26485e-04, -5.42181e-03, -5.59305e-03, 1.22825e-02, 1.23868e-02,
  286.             6.68835e-03, -1.03303e-02, -9.51903e-03, 2.70021e-04, -2.57084e-02,
  287.             -1.32430e-02, 0.00000e+00, -3.81000e-02, -3.16810e-03, 0.00000e+00,
  288.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  289.             0.00000e+00, -9.05762e-04, -2.14590e-03, -1.17824e-03, 3.66732e+00,
  290.             -3.79729e-04, -6.13966e-03, -5.09082e-03, -1.96332e-03, -3.08280e-03,
  291.             -9.75222e-04, 4.03315e+00, -2.52710e-01, 0.00000e+00, 0.00000e+00,
  292.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  293.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  294.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  295.         },
  296.         // N2 DENSITY
  297.         {
  298.             1.16112e+00, 0.00000e+00, 0.00000e+00, 3.33725e-02, 0.00000e+00,
  299.             3.48637e-02, -5.44368e-03, 0.00000e+00, -6.73940e-02, 1.74754e-01,
  300.             0.00000e+00, 0.00000e+00, 0.00000e+00, 1.74712e+02, 0.00000e+00,
  301.             1.26733e-01, 0.00000e+00, 1.03154e+02, 5.52075e-02, 0.00000e+00,
  302.             0.00000e+00, 8.13525e-04, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  303.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  304.             0.00000e+00, -2.50482e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  305.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.48894e-03,
  306.             6.16053e-04, -5.79716e-04, 2.95482e-03, 8.47001e-02, 1.70147e-01,
  307.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  308.             0.00000e+00, 2.47425e-05, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  309.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  310.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  311.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  312.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  313.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  314.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  315.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  316.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  317.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  318.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  319.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  320.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  321.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  322.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  323.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  324.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  325.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  326.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  327.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  328.         },
  329.         // TOTAL MASS
  330.         {
  331.             9.44846e-01, 0.00000e+00, 0.00000e+00, -3.08617e-02, 0.00000e+00,
  332.             -2.44019e-02, 6.48607e-03, 0.00000e+00, 3.08181e-02, 4.59392e-02,
  333.             0.00000e+00, 0.00000e+00, 0.00000e+00, 1.74712e+02, 0.00000e+00,
  334.             2.13260e-02, 0.00000e+00, -3.56958e+02, 0.00000e+00, 1.82278e-04,
  335.             0.00000e+00, 3.07472e-04, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  336.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  337.             0.00000e+00, 0.00000e+00, 3.83054e-03, 0.00000e+00, 0.00000e+00,
  338.             -1.93065e-03, -1.45090e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  339.             0.00000e+00, -1.23493e-03, 1.36736e-03, 8.47001e-02, 1.70147e-01,
  340.             3.71469e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  341.             5.10250e-03, 2.47425e-05, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  342.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  343.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  344.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  345.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  346.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  347.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  348.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  349.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  350.             0.00000e+00, 3.68756e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  351.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  352.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  353.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  354.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  355.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  356.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  357.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  358.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  359.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  360.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  361.         },
  362.         // O2 DENSITY
  363.         {
  364.             1.35580e+00, 1.44816e-01, 0.00000e+00, 6.07767e-02, 0.00000e+00,
  365.             2.94777e-02, 7.46900e-02, 0.00000e+00, -9.23822e-02, 8.57342e-02,
  366.             0.00000e+00, 0.00000e+00, 0.00000e+00, 2.38636e+01, 0.00000e+00,
  367.             7.71653e-02, 0.00000e+00, 8.18751e+01, 1.87736e-02, 0.00000e+00,
  368.             0.00000e+00, 1.49667e-02, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  369.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  370.             0.00000e+00, -3.67874e+02, 5.48158e-03, 0.00000e+00, 0.00000e+00,
  371.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  372.             0.00000e+00, 0.00000e+00, 0.00000e+00, 8.47001e-02, 1.70147e-01,
  373.             1.22631e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  374.             8.17187e-03, 3.71617e-05, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  375.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  376.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.10826e-03,
  377.             -3.13640e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  378.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  379.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  380.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  381.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  382.             -7.35742e-02, -5.00266e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  383.             0.00000e+00, 1.94965e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  384.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  385.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  386.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  387.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  388.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  389.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  390.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  391.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  392.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  393.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  394.         },
  395.         // AR DENSITY
  396.         {
  397.             1.04761e+00, 2.00165e-01, 2.37697e-01, 3.68552e-02, 0.00000e+00,
  398.             3.57202e-02, -2.14075e-01, 0.00000e+00, -1.08018e-01, -3.73981e-01,
  399.             0.00000e+00, 3.10022e-02, -1.16305e-03, -2.07596e+01, 0.00000e+00,
  400.             8.64502e-02, 0.00000e+00, 9.74908e+01, 5.16707e-02, 0.00000e+00,
  401.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  402.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  403.             0.00000e+00, 3.46193e+02, 1.34297e-02, 0.00000e+00, 0.00000e+00,
  404.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -3.48509e-03,
  405.             -1.54689e-04, 0.00000e+00, 0.00000e+00, 8.47001e-02, 1.70147e-01,
  406.             1.47753e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  407.             1.89320e-02, 3.68181e-05, 1.32570e-02, 0.00000e+00, 0.00000e+00,
  408.             3.59719e-03, 7.44328e-03, -1.00023e-03, -6.50528e+03, 0.00000e+00,
  409.             1.03485e-02, -1.00983e-03, -4.06916e-03, -6.60864e+01, -1.71533e-02,
  410.             1.10605e-02, 1.20300e-02, -5.20034e-03, 0.00000e+00, 0.00000e+00,
  411.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  412.             -2.62769e+03, 7.13755e-03, 4.17999e-03, 0.00000e+00, 1.25910e+04,
  413.             0.00000e+00, 0.00000e+00, 0.00000e+00, -2.23595e-03, 4.60217e-03,
  414.             5.71794e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  415.             -3.18353e-02, -2.35526e-02, -1.36189e-02, 0.00000e+00, 0.00000e+00,
  416.             0.00000e+00, 2.03522e-02, -6.67837e+01, -1.09724e-03, 0.00000e+00,
  417.             -1.38821e-02, 1.60468e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  418.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.51574e-02,
  419.             -5.44470e-04, 0.00000e+00, 7.28224e-02, 6.59413e-02, 0.00000e+00,
  420.             -5.15692e-03, 0.00000e+00, 0.00000e+00, -3.70367e+03, 0.00000e+00,
  421.             0.00000e+00, 1.36131e-02, 5.38153e-03, 0.00000e+00, 4.76285e+00,
  422.             -1.75677e-02, 2.26301e-02, 0.00000e+00, 1.76631e-02, 4.77162e-03,
  423.             0.00000e+00, 5.39354e+00, 0.00000e+00, -7.51710e-03, 0.00000e+00,
  424.             0.00000e+00, -8.82736e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  425.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  426.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  427.         },
  428.         // H DENSITY
  429.         {
  430.             1.26376e+00, -2.14304e-01, -1.49984e-01, 2.30404e-01, 2.98237e-02,
  431.             2.68673e-02, 2.96228e-01, 2.21900e-02, -2.07655e-02, 4.52506e-01,
  432.             1.20105e-01, 3.24420e-02, 4.24816e-02, -9.14313e+00, 0.00000e+00,
  433.             2.47178e-02, -2.88229e-02, 8.12805e+01, 5.10380e-02, -5.80611e-03,
  434.             2.51236e-05, -1.24083e-02, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  435.             1.58727e-01, -3.48190e-02, 0.00000e+00, 0.00000e+00, 2.89885e-05,
  436.             0.00000e+00, 1.53595e+02, -1.68604e-02, 0.00000e+00, 1.01015e-02,
  437.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.84552e-04,
  438.             -1.22181e-03, 0.00000e+00, 0.00000e+00, 8.47001e-02, 1.70147e-01,
  439.             -1.04927e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, -5.91313e-03,
  440.             -2.30501e-02, 3.14758e-05, 0.00000e+00, 0.00000e+00, 1.26956e-02,
  441.             8.35489e-03, 3.10513e-04, 0.00000e+00, 3.42119e+03, -2.45017e-03,
  442.             -4.27154e-04, 5.45152e-04, 1.89896e-03, 2.89121e+01, -6.49973e-03,
  443.             -1.93855e-02, -1.48492e-02, 0.00000e+00, -5.10576e-02, 7.87306e-02,
  444.             9.51981e-02, -1.49422e+04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  445.             2.65503e+02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  446.             0.00000e+00, 0.00000e+00, 0.00000e+00, 6.37110e-03, 3.24789e-04,
  447.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  448.             6.14274e-02, 1.00376e-02, -8.41083e-04, 0.00000e+00, 0.00000e+00,
  449.             0.00000e+00, -1.27099e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  450.             -3.94077e-03, -1.28601e-02, -7.97616e-03, 0.00000e+00, 0.00000e+00,
  451.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  452.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  453.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  454.             0.00000e+00, -6.71465e-03, -1.69799e-03, 1.93772e-03, 3.81140e+00,
  455.             -7.79290e-03, -1.82589e-02, -1.25860e-02, -1.04311e-02, -3.02465e-03,
  456.             2.43063e-03, 3.63237e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  457.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  458.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  459.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  460.         },
  461.         // N DENSITY
  462.         {
  463.             7.09557e+01, -3.26740e-01, 0.00000e+00, -5.16829e-01, -1.71664e-03,
  464.             9.09310e-02, -6.71500e-01, -1.47771e-01, -9.27471e-02, -2.30862e-01,
  465.             -1.56410e-01, 1.34455e-02, -1.19717e-01, 2.52151e+00, 0.00000e+00,
  466.             -2.41582e-01, 5.92939e-02, 4.39756e+00, 9.15280e-02, 4.41292e-03,
  467.             0.00000e+00, 8.66807e-03, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  468.             1.58727e-01, 9.74701e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  469.             0.00000e+00, 6.70217e+01, -1.31660e-03, 0.00000e+00, -1.65317e-02,
  470.             0.00000e+00, 0.00000e+00, 8.50247e-02, 2.77428e+01, 4.98658e-03,
  471.             6.15115e-03, 9.50156e-03, -2.12723e-02, 8.47001e-02, 1.70147e-01,
  472.             -2.38645e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.37380e-03,
  473.             -8.41918e-03, 2.80145e-05, 7.12383e-03, 0.00000e+00, -1.66209e-02,
  474.             1.03533e-04, -1.68898e-02, 0.00000e+00, 3.64526e+03, 0.00000e+00,
  475.             6.54077e-03, 3.69130e-04, 9.94419e-04, 8.42803e+01, -1.16124e-02,
  476.             -7.74414e-03, -1.68844e-03, 1.42809e-03, -1.92955e-03, 1.17225e-01,
  477.             -2.41512e-02, 1.50521e+04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  478.             1.60261e+03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  479.             0.00000e+00, 0.00000e+00, 0.00000e+00, -3.54403e-04, -1.87270e-02,
  480.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  481.             2.76439e-02, 6.43207e-03, -3.54300e-02, 0.00000e+00, 0.00000e+00,
  482.             0.00000e+00, -2.80221e-02, 8.11228e+01, -6.75255e-04, 0.00000e+00,
  483.             -1.05162e-02, -3.48292e-03, -6.97321e-03, 0.00000e+00, 0.00000e+00,
  484.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  485.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  486.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  487.             0.00000e+00, -1.45546e-03, -1.31970e-02, -3.57751e-03, -1.09021e+00,
  488.             -1.50181e-02, -7.12841e-03, -6.64590e-03, -3.52610e-03, -1.87773e-02,
  489.             -2.22432e-03, -3.93895e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  490.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  491.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  492.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  493.         },
  494.         // HOT O DENSITY
  495.         {
  496.             6.04050e-02, 1.57034e+00, 2.99387e-02, 0.00000e+00, 0.00000e+00,
  497.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -1.51018e+00,
  498.             0.00000e+00, 0.00000e+00, 0.00000e+00, -8.61650e+00, 1.26454e-02,
  499.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  500.             0.00000e+00, 5.50878e-03, 0.00000e+00, 0.00000e+00, 8.66784e-02,
  501.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  502.             0.00000e+00, 0.00000e+00, 6.23881e-02, 0.00000e+00, 0.00000e+00,
  503.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  504.             0.00000e+00, 0.00000e+00, 0.00000e+00, 8.47001e-02, 1.70147e-01,
  505.             -9.45934e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  506.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  507.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  508.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  509.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  510.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  511.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  512.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  513.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  514.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  515.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  516.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  517.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  518.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  519.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  520.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  521.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  522.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  523.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  524.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  525.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  526.         }
  527.     };

  528.     /** NRLMSISE-00 data: ps[150]. */
  529.     private static final double[] PS = {
  530.         9.56827e-01, 6.20637e-02, 3.18433e-02, 0.00000e+00, 0.00000e+00,
  531.         3.94900e-02, 0.00000e+00, 0.00000e+00, -9.24882e-03, -7.94023e-03,
  532.         0.00000e+00, 0.00000e+00, 0.00000e+00, 1.74712e+02, 0.00000e+00,
  533.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  534.         0.00000e+00, 2.74677e-03, 0.00000e+00, 1.54951e-02, 8.66784e-02,
  535.         1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  536.         0.00000e+00, 0.00000e+00, 0.00000e+00, -6.99007e-04, 0.00000e+00,
  537.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  538.         0.00000e+00, 1.24362e-02, -5.28756e-03, 8.47001e-02, 1.70147e-01,
  539.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  540.         0.00000e+00, 2.47425e-05, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  541.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  542.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  543.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  544.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  545.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  546.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  547.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  548.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  549.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  550.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  551.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  552.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  553.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  554.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  555.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  556.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  557.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  558.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  559.         0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  560.     };

  561.     /** NRLMSISE-00 data: TURBO pdl[2][25]. */
  562.     private static final double[][] PDL = {
  563.         {
  564.             1.09930e+00, 3.90631e+00, 3.07165e+00, 9.86161e-01, 1.63536e+01,
  565.             4.63830e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  566.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  567.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  568.             0.00000e+00, 0.00000e+00, 1.28840e+00, 3.10302e-02, 1.18339e-01
  569.         },
  570.         {
  571.             1.00000e+00, 7.00000e-01, 1.15020e+00, 3.44689e+00, 1.28840e+00,
  572.             1.00000e+00, 1.08738e+00, 1.22947e+00, 1.10016e+00, 7.34129e-01,
  573.             1.15241e+00, 2.22784e+00, 7.95046e-01, 4.01612e+00, 4.47749e+00,
  574.             1.23435e+02, -7.60535e-02, 1.68986e-06, 7.44294e-01, 1.03604e+00,
  575.             1.72783e+02, 1.15020e+00, 3.44689e+00, -7.46230e-01, 9.49154e-01
  576.         }
  577.     };

  578.     /** NRLMSISE-00 data: LOWER BOUNDARY ptm[10]. */
  579.     private static final double[] PTM = {
  580.         1.04130e+03, 3.86000e+02, 1.95000e+02, 1.66728e+01, 2.13000e+02,
  581.         1.20000e+02, 2.40000e+02, 1.87000e+02, -2.00000e+00, 0.00000e+00
  582.     };

  583.     /** NRLMSISE-00 data: pdm[8][10]. */
  584.     private static final double[][] PDM = {
  585.         {
  586.             2.45600e+07, 6.71072e-06, 1.00000e+02, 0.00000e+00, 1.10000e+02,
  587.             1.00000e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  588.         },
  589.         {
  590.             8.59400E+10, 1.00000e+00, 1.05000e+02, -8.00000e+00, 1.10000e+02,
  591.             1.00000e+01, 9.00000e+01, 2.00000e+00, 0.00000e+00, 0.00000e+00
  592.         },
  593.         {
  594.             2.81000E+11, 0.00000e+00, 1.05000e+02, 2.80000e+01, 2.89500e+01,
  595.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  596.         },
  597.         {
  598.             3.30000E+10, 2.68270e-01, 1.05000e+02, 1.00000e+00, 1.10000e+02,
  599.             1.00000e+01, 1.10000e+02, -1.00000e+01, 0.00000e+00, 0.00000e+00
  600.         },
  601.         {
  602.             1.33000e+09, 1.19615e-02, 1.05000e+02, 0.00000e+00, 1.10000e+02,
  603.             1.00000e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00
  604.         },
  605.         {
  606.             1.76100e+05, 1.00000e+00, 9.50000e+01, -8.00000e+00, 1.10000e+02,
  607.             1.00000e+01, 9.00000e+01, 2.00000e+00, 0.00000e+00, 0.00000e+00,
  608.         },
  609.         {
  610.             1.00000e+07, 1.00000e+00, 1.05000e+02, -8.00000e+00, 1.10000e+02,
  611.             1.00000e+01, 9.00000e+01, 2.00000e+00, 0.00000e+00, 0.00000e+00
  612.         },
  613.         {
  614.             1.00000e+06, 1.00000e+00, 1.05000e+02, -8.00000e+00, 5.50000e+02,
  615.             7.60000e+01, 9.00000e+01, 2.00000e+00, 0.00000e+00, 4.00000e+03
  616.         }
  617.     };

  618.     /** NRLMSISE-00 data: ptl[4][100]. */
  619.     private static final double[][] PTL = {
  620.         // TN1(2)
  621.         {
  622.             1.00858e+00, 4.56011e-02, -2.22972e-02, -5.44388e-02, 5.23136e-04,
  623.             -1.88849e-02, 5.23707e-02, -9.43646e-03, 6.31707e-03, -7.80460e-02,
  624.             -4.88430e-02, 0.00000e+00, 0.00000e+00, -7.60250e+00, 0.00000e+00,
  625.             -1.44635e-02, -1.76843e-02, -1.21517e+02, 2.85647e-02, 0.00000e+00,
  626.             0.00000e+00, 6.31792e-04, 0.00000e+00, 5.77197e-03, 8.66784e-02,
  627.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  628.             0.00000e+00, -8.90272e+03, 3.30611e-03, 3.02172e-03, 0.00000e+00,
  629.             -2.13673e-03, -3.20910e-04, 0.00000e+00, 0.00000e+00, 2.76034e-03,
  630.             2.82487e-03, -2.97592e-04, -4.21534e-03, 8.47001e-02, 1.70147e-01,
  631.             8.96456e-03, 0.00000e+00, -1.08596e-02, 0.00000e+00, 0.00000e+00,
  632.             5.57917e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  633.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  634.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  635.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  636.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  637.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  638.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  639.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  640.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  641.             0.00000e+00, 9.65405e-03, 0.00000e+00, 0.00000e+00, 2.00000e+00
  642.         },
  643.         // TN1(3)
  644.         {
  645.             9.39664e-01, 8.56514e-02, -6.79989e-03, 2.65929e-02, -4.74283e-03,
  646.             1.21855e-02, -2.14905e-02, 6.49651e-03, -2.05477e-02, -4.24952e-02,
  647.             0.00000e+00, 0.00000e+00, 0.00000e+00, 1.19148e+01, 0.00000e+00,
  648.             1.18777e-02, -7.28230e-02, -8.15965e+01, 1.73887e-02, 0.00000e+00,
  649.             0.00000e+00, 0.00000e+00, -1.44691e-02, 2.80259e-04, 8.66784e-02,
  650.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  651.             0.00000e+00, 2.16584e+02, 3.18713e-03, 7.37479e-03, 0.00000e+00,
  652.             -2.55018e-03, -3.92806e-03, 0.00000e+00, 0.00000e+00, -2.89757e-03,
  653.             -1.33549e-03, 1.02661e-03, 3.53775e-04, 8.47001e-02, 1.70147e-01,
  654.             -9.17497e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  655.             3.56082e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  656.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  657.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  658.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  659.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  660.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  661.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  662.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  663.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  664.             0.00000e+00, -1.00902e-02, 0.00000e+00, 0.00000e+00, 2.00000e+00
  665.         },
  666.         // TN1(4)
  667.         {
  668.             9.85982e-01, -4.55435e-02, 1.21106e-02, 2.04127e-02, -2.40836e-03,
  669.             1.11383e-02, -4.51926e-02, 1.35074e-02, -6.54139e-03, 1.15275e-01,
  670.             1.28247e-01, 0.00000e+00, 0.00000e+00, -5.30705e+00, 0.00000e+00,
  671.             -3.79332e-02, -6.24741e-02, 7.71062e-01, 2.96315e-02, 0.00000e+00,
  672.             0.00000e+00, 0.00000e+00, 6.81051e-03, -4.34767e-03, 8.66784e-02,
  673.             1.58727e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  674.             0.00000e+00, 1.07003e+01, -2.76907e-03, 4.32474e-04, 0.00000e+00,
  675.             1.31497e-03, -6.47517e-04, 0.00000e+00, -2.20621e+01, -1.10804e-03,
  676.             -8.09338e-04, 4.18184e-04, 4.29650e-03, 8.47001e-02, 1.70147e-01,
  677.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  678.             -4.04337e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  679.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  680.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -9.52550e-04,
  681.             8.56253e-04, 4.33114e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  682.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.21223e-03,
  683.             2.38694e-04, 9.15245e-04, 1.28385e-03, 8.67668e-04, -5.61425e-06,
  684.             1.04445e+00, 3.41112e+01, 0.00000e+00, -8.40704e-01, -2.39639e+02,
  685.             7.06668e-01, -2.05873e+01, -3.63696e-01, 2.39245e+01, 0.00000e+00,
  686.             -1.06657e-03, -7.67292e-04, 1.54534e-04, 0.00000e+00, 0.00000e+00,
  687.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  688.         },
  689.         // TN1(5) TN2(1)
  690.         {
  691.             1.00320e+00, 3.83501e-02, -2.38983e-03, 2.83950e-03, 4.20956e-03,
  692.             5.86619e-04, 2.19054e-02, -1.00946e-02, -3.50259e-03, 4.17392e-02,
  693.             -8.44404e-03, 0.00000e+00, 0.00000e+00, 4.96949e+00, 0.00000e+00,
  694.             -7.06478e-03, -1.46494e-02, 3.13258e+01, -1.86493e-03, 0.00000e+00,
  695.             -1.67499e-02, 0.00000e+00, 0.00000e+00, 5.12686e-04, 8.66784e-02,
  696.             1.58727e-01, -4.64167e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  697.             4.37353e-03, -1.99069e+02, 0.00000e+00, -5.34884e-03, 0.00000e+00,
  698.             1.62458e-03, 2.93016e-03, 2.67926e-03, 5.90449e+02, 0.00000e+00,
  699.             0.00000e+00, -1.17266e-03, -3.58890e-04, 8.47001e-02, 1.70147e-01,
  700.             0.00000e+00, 0.00000e+00, 1.38673e-02, 0.00000e+00, 0.00000e+00,
  701.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  702.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  703.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.60571e-03,
  704.             6.28078e-04, 5.05469e-05, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  705.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -1.57829e-03,
  706.             -4.00855e-04, 5.04077e-05, -1.39001e-03, -2.33406e-03, -4.81197e-04,
  707.             1.46758e+00, 6.20332e+00, 0.00000e+00, 3.66476e-01, -6.19760e+01,
  708.             3.09198e-01, -1.98999e+01, 0.00000e+00, -3.29933e+02, 0.00000e+00,
  709.             -1.10080e-03, -9.39310e-05, 1.39638e-04, 0.00000e+00, 0.00000e+00,
  710.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  711.         }
  712.     };

  713.     /** NRLMSISE-00 data: pma[10][100]. */
  714.     private static final double[][] PMA = {
  715.         // TN2(2)
  716.         {
  717.             9.81637e-01, -1.41317e-03, 3.87323e-02, 0.00000e+00, 0.00000e+00,
  718.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -3.58707e-02,
  719.             -8.63658e-03, 0.00000e+00, 0.00000e+00, -2.02226e+00, 0.00000e+00,
  720.             -8.69424e-03, -1.91397e-02, 8.76779e+01, 4.52188e-03, 0.00000e+00,
  721.             2.23760e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  722.             0.00000e+00, -7.07572e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  723.             -4.11210e-03, 3.50060e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  724.             0.00000e+00, 0.00000e+00, -8.36657e-03, 1.61347e+01, 0.00000e+00,
  725.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  726.             0.00000e+00, 0.00000e+00, -1.45130e-02, 0.00000e+00, 0.00000e+00,
  727.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  728.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  729.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.24152e-03,
  730.             6.43365e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  731.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.33255e-03,
  732.             2.42657e-03, 1.60666e-03, -1.85728e-03, -1.46874e-03, -4.79163e-06,
  733.             1.22464e+00, 3.53510e+01, 0.00000e+00, 4.49223e-01, -4.77466e+01,
  734.             4.70681e-01, 8.41861e+00, -2.88198e-01, 1.67854e+02, 0.00000e+00,
  735.             7.11493e-04, 6.05601e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  736.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  737.         },
  738.         // TN2(3)
  739.         {
  740.             1.00422e+00, -7.11212e-03, 5.24480e-03, 0.00000e+00, 0.00000e+00,
  741.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -5.28914e-02,
  742.             -2.41301e-02, 0.00000e+00, 0.00000e+00, -2.12219e+01, -1.03830e-02,
  743.             -3.28077e-03, 1.65727e-02, 1.68564e+00, -6.68154e-03, 0.00000e+00,
  744.             1.45155e-02, 0.00000e+00, 8.42365e-03, 0.00000e+00, 0.00000e+00,
  745.             0.00000e+00, -4.34645e-03, 0.00000e+00, 0.00000e+00, 2.16780e-02,
  746.             0.00000e+00, -1.38459e+02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  747.             0.00000e+00, 0.00000e+00, 7.04573e-03, -4.73204e+01, 0.00000e+00,
  748.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  749.             0.00000e+00, 0.00000e+00, 1.08767e-02, 0.00000e+00, 0.00000e+00,
  750.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  751.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -8.08279e-03,
  752.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 5.21769e-04,
  753.             -2.27387e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  754.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 3.26769e-03,
  755.             3.16901e-03, 4.60316e-04, -1.01431e-04, 1.02131e-03, 9.96601e-04,
  756.             1.25707e+00, 2.50114e+01, 0.00000e+00, 4.24472e-01, -2.77655e+01,
  757.             3.44625e-01, 2.75412e+01, 0.00000e+00, 7.94251e+02, 0.00000e+00,
  758.             2.45835e-03, 1.38871e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  759.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  760.         },
  761.         // TN2(4) TN3(1)
  762.         {
  763.             1.01890e+00, -2.46603e-02, 1.00078e-02, 0.00000e+00, 0.00000e+00,
  764.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -6.70977e-02,
  765.             -4.02286e-02, 0.00000e+00, 0.00000e+00, -2.29466e+01, -7.47019e-03,
  766.             2.26580e-03, 2.63931e-02, 3.72625e+01, -6.39041e-03, 0.00000e+00,
  767.             9.58383e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  768.             0.00000e+00, -1.85291e-03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  769.             0.00000e+00, 1.39717e+02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  770.             0.00000e+00, 0.00000e+00, 9.19771e-03, -3.69121e+02, 0.00000e+00,
  771.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  772.             0.00000e+00, 0.00000e+00, -1.57067e-02, 0.00000e+00, 0.00000e+00,
  773.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  774.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -7.07265e-03,
  775.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.92953e-03,
  776.             -2.77739e-03, -4.40092e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  777.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.47280e-03,
  778.             2.95035e-04, -1.81246e-03, 2.81945e-03, 4.27296e-03, 9.78863e-04,
  779.             1.40545e+00, -6.19173e+00, 0.00000e+00, 0.00000e+00, -7.93632e+01,
  780.             4.44643e-01, -4.03085e+02, 0.00000e+00, 1.15603e+01, 0.00000e+00,
  781.             2.25068e-03, 8.48557e-04, -2.98493e-04, 0.00000e+00, 0.00000e+00,
  782.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  783.         },
  784.         // TN3(2)
  785.         {
  786.             9.75801e-01, 3.80680e-02, -3.05198e-02, 0.00000e+00, 0.00000e+00,
  787.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 3.85575e-02,
  788.             5.04057e-02, 0.00000e+00, 0.00000e+00, -1.76046e+02, 1.44594e-02,
  789.             -1.48297e-03, -3.68560e-03, 3.02185e+01, -3.23338e-03, 0.00000e+00,
  790.             1.53569e-02, 0.00000e+00, -1.15558e-02, 0.00000e+00, 0.00000e+00,
  791.             0.00000e+00, 4.89620e-03, 0.00000e+00, 0.00000e+00, -1.00616e-02,
  792.             -8.21324e-03, -1.57757e+02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  793.             0.00000e+00, 0.00000e+00, 6.63564e-03, 4.58410e+01, 0.00000e+00,
  794.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  795.             0.00000e+00, 0.00000e+00, -2.51280e-02, 0.00000e+00, 0.00000e+00,
  796.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  797.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 9.91215e-03,
  798.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -8.73148e-04,
  799.             -1.29648e-03, -7.32026e-05, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  800.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -4.68110e-03,
  801.             -4.66003e-03, -1.31567e-03, -7.39390e-04, 6.32499e-04, -4.65588e-04,
  802.             -1.29785e+00, -1.57139e+02, 0.00000e+00, 2.58350e-01, -3.69453e+01,
  803.             4.10672e-01, 9.78196e+00, -1.52064e-01, -3.85084e+03, 0.00000e+00,
  804.             -8.52706e-04, -1.40945e-03, -7.26786e-04, 0.00000e+00, 0.00000e+00,
  805.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  806.         },
  807.         // TN3(3)
  808.         {
  809.             9.60722e-01, 7.03757e-02, -3.00266e-02, 0.00000e+00, 0.00000e+00,
  810.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.22671e-02,
  811.             4.10423e-02, 0.00000e+00, 0.00000e+00, -1.63070e+02, 1.06073e-02,
  812.             5.40747e-04, 7.79481e-03, 1.44908e+02, 1.51484e-04, 0.00000e+00,
  813.             1.97547e-02, 0.00000e+00, -1.41844e-02, 0.00000e+00, 0.00000e+00,
  814.             0.00000e+00, 5.77884e-03, 0.00000e+00, 0.00000e+00, 9.74319e-03,
  815.             0.00000e+00, -2.88015e+03, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  816.             0.00000e+00, 0.00000e+00, -4.44902e-03, -2.92760e+01, 0.00000e+00,
  817.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  818.             0.00000e+00, 0.00000e+00, 2.34419e-02, 0.00000e+00, 0.00000e+00,
  819.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  820.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 5.36685e-03,
  821.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -4.65325e-04,
  822.             -5.50628e-04, 3.31465e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  823.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.06179e-03,
  824.             -3.08575e-03, -7.93589e-04, -1.08629e-04, 5.95511e-04, -9.05050e-04,
  825.             1.18997e+00, 4.15924e+01, 0.00000e+00, -4.72064e-01, -9.47150e+02,
  826.             3.98723e-01, 1.98304e+01, 0.00000e+00, 3.73219e+03, 0.00000e+00,
  827.             -1.50040e-03, -1.14933e-03, -1.56769e-04, 0.00000e+00, 0.00000e+00,
  828.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  829.         },
  830.         // TN3(4)
  831.         {
  832.             1.03123e+00, -7.05124e-02, 8.71615e-03, 0.00000e+00, 0.00000e+00,
  833.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -3.82621e-02,
  834.             -9.80975e-03, 0.00000e+00, 0.00000e+00, 2.89286e+01, 9.57341e-03,
  835.             0.00000e+00, 0.00000e+00, 8.66153e+01, 7.91938e-04, 0.00000e+00,
  836.             0.00000e+00, 0.00000e+00, 4.68917e-03, 0.00000e+00, 0.00000e+00,
  837.             0.00000e+00, 7.86638e-03, 0.00000e+00, 0.00000e+00, 9.90827e-03,
  838.             0.00000e+00, 6.55573e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  839.             0.00000e+00, 0.00000e+00, 0.00000e+00, -4.00200e+01, 0.00000e+00,
  840.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  841.             0.00000e+00, 0.00000e+00, 7.07457e-03, 0.00000e+00, 0.00000e+00,
  842.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  843.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 5.72268e-03,
  844.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.04970e-04,
  845.             1.21560e-03, -8.05579e-06, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  846.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.49941e-03,
  847.             -4.57256e-04, -1.59311e-04, 2.96481e-04, -1.77318e-03, -6.37918e-04,
  848.             1.02395e+00, 1.28172e+01, 0.00000e+00, 1.49903e-01, -2.63818e+01,
  849.             0.00000e+00, 4.70628e+01, -2.22139e-01, 4.82292e-02, 0.00000e+00,
  850.             -8.67075e-04, -5.86479e-04, 5.32462e-04, 0.00000e+00, 0.00000e+00,
  851.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  852.         },
  853.         // TN3(5) SURFACE TEMP TSL
  854.         {
  855.             1.00828e+00, -9.10404e-02, -2.26549e-02, 0.00000e+00, 0.00000e+00,
  856.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -2.32420e-02,
  857.             -9.08925e-03, 0.00000e+00, 0.00000e+00, 3.36105e+01, 0.00000e+00,
  858.             0.00000e+00, 0.00000e+00, -1.24957e+01, -5.87939e-03, 0.00000e+00,
  859.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  860.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  861.             0.00000e+00, 2.79765e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  862.             0.00000e+00, 0.00000e+00, 0.00000e+00, 2.01237e+03, 0.00000e+00,
  863.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  864.             0.00000e+00, 0.00000e+00, -1.75553e-02, 0.00000e+00, 0.00000e+00,
  865.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  866.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  867.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 3.29699e-03,
  868.             1.26659e-03, 2.68402e-04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  869.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 1.17894e-03,
  870.             1.48746e-03, 1.06478e-04, 1.34743e-04, -2.20939e-03, -6.23523e-04,
  871.             6.36539e-01, 1.13621e+01, 0.00000e+00, -3.93777e-01, 2.38687e+03,
  872.             0.00000e+00, 6.61865e+02, -1.21434e-01, 9.27608e+00, 0.00000e+00,
  873.             1.68478e-04, 1.24892e-03, 1.71345e-03, 0.00000e+00, 0.00000e+00,
  874.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  875.         },
  876.         // TGN3(2) SURFACE GRAD TSLG
  877.         {
  878.             1.57293e+00, -6.78400e-01, 6.47500e-01, 0.00000e+00, 0.00000e+00,
  879.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -7.62974e-02,
  880.             -3.60423e-01, 0.00000e+00, 0.00000e+00, 1.28358e+02, 0.00000e+00,
  881.             0.00000e+00, 0.00000e+00, 4.68038e+01, 0.00000e+00, 0.00000e+00,
  882.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  883.             0.00000e+00, -1.67898e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  884.             0.00000e+00, 2.90994e+04, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  885.             0.00000e+00, 0.00000e+00, 0.00000e+00, 3.15706e+01, 0.00000e+00,
  886.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  887.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  888.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  889.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  890.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  891.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  892.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  893.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  894.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  895.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  896.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  897.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  898.         },
  899.         // TGN2(1) TGN1(2)
  900.         {
  901.             8.60028e-01, 3.77052e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  902.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -1.17570e+00,
  903.             0.00000e+00, 0.00000e+00, 0.00000e+00, 7.77757e-03, 0.00000e+00,
  904.             0.00000e+00, 0.00000e+00, 1.01024e+02, 0.00000e+00, 0.00000e+00,
  905.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  906.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  907.             0.00000e+00, 6.54251e+02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  908.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  909.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  910.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  911.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  912.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  913.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  914.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  915.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, -1.56959e-02,
  916.             1.91001e-02, 3.15971e-02, 1.00982e-02, -6.71565e-03, 2.57693e-03,
  917.             1.38692e+00, 2.82132e-01, 0.00000e+00, 0.00000e+00, 3.81511e+02,
  918.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  919.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  920.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  921.         },
  922.         // TGN3(1) TGN2(2)
  923.         {
  924.             1.06029e+00, -5.25231e-02, 3.73034e-01, 0.00000e+00, 0.00000e+00,
  925.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 3.31072e-02,
  926.             -3.88409e-01, 0.00000e+00, 0.00000e+00, -1.65295e+02, -2.13801e-01,
  927.             -4.38916e-02, -3.22716e-01, -8.82393e+01, 1.18458e-01, 0.00000e+00,
  928.             -4.35863e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  929.             0.00000e+00, -1.19782e-01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  930.             0.00000e+00, 2.62229e+01, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  931.             0.00000e+00, 0.00000e+00, 0.00000e+00, -5.37443e+01, 0.00000e+00,
  932.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  933.             0.00000e+00, 0.00000e+00, -4.55788e-01, 0.00000e+00, 0.00000e+00,
  934.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  935.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  936.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 3.84009e-02,
  937.             3.96733e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  938.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 5.05494e-02,
  939.             7.39617e-02, 1.92200e-02, -8.46151e-03, -1.34244e-02, 1.96338e-02,
  940.             1.50421e+00, 1.88368e+01, 0.00000e+00, 0.00000e+00, -5.13114e+01,
  941.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  942.             5.11923e-02, 3.61225e-02, 0.00000e+00, 0.00000e+00, 0.00000e+00,
  943.             0.00000e+00, 0.00000e+00, 0.00000e+00, 0.00000e+00, 2.00000e+00
  944.         }
  945.     };

  946.     /**  NRLMSISE-00 data: MIDDLE ATMOSPHERE AVERAGES pavgm[10]. */
  947.     private static final double[] PAVGM = {
  948.         2.61000e+02, 2.64000e+02, 2.29000e+02, 2.17000e+02, 2.17000e+02,
  949.         2.23000e+02, 2.86760e+02, -2.93940e+00, 2.50000e+00, 0.00000e+00
  950.     };

  951.     // Fields

  952.     /** External data container. */
  953.     private final NRLMSISE00InputParameters inputParams;

  954.     /** Sun position. */
  955.     private PVCoordinatesProvider sun;

  956.     /** Earth body shape. */
  957.     private final BodyShape earth;

  958.     /** Switches for main effects. */
  959.     private final int[] sw;

  960.     /** Switches for cross effects. */
  961.     private final int[] swc;

  962.     /** Constructor.
  963.      * <p>
  964.      * The model is constructed with all switches set to 1.
  965.      * </p>
  966.      * <p>
  967.      * Parameters are mandatory only for the
  968.      * {@link #getDensity(AbsoluteDate, Vector3D, Frame) getDensity()} and
  969.      * {@link #getVelocity(AbsoluteDate, Vector3D, Frame) getVelocity()} methods.
  970.      * </p>
  971.      * @param parameters the solar and magnetic activity data
  972.      * @param sun the Sun position
  973.      * @param earth the Earth body shape
  974.      */
  975.     public NRLMSISE00(final NRLMSISE00InputParameters parameters,
  976.                       final PVCoordinatesProvider sun,
  977.                       final BodyShape earth) {
  978.         this(parameters, sun, earth, allOnes(), allOnes());
  979.     }

  980.     /** Constructor.
  981.      * <p>
  982.      * The model is constructed with all switches set to 1.
  983.      * </p>
  984.      * <p>
  985.      * Parameters are mandatory only for the
  986.      * {@link #getDensity(AbsoluteDate, Vector3D, Frame) getDensity()} and
  987.      * {@link #getVelocity(AbsoluteDate, Vector3D, Frame) getVelocity()} methods.
  988.      * </p>
  989.      * @param parameters the solar and magnetic activity data
  990.      * @param sun the Sun position
  991.      * @param earth the Earth body shape
  992.      * @param sw switches for main effects
  993.      * @param swc switches for cross effects
  994.      */
  995.     private NRLMSISE00(final NRLMSISE00InputParameters parameters,
  996.                       final PVCoordinatesProvider sun,
  997.                       final BodyShape earth,
  998.                       final int[] sw,
  999.                       final int[] swc) {
  1000.         this.inputParams = parameters;
  1001.         this.sun         = sun;
  1002.         this.earth       = earth;
  1003.         this.sw          = sw;
  1004.         this.swc         = swc;
  1005.     }

  1006.     /** Change a switch.
  1007.      * <p>
  1008.      * This method creates a new instance, the current instance is
  1009.      * not changed at all!
  1010.      * </p>
  1011.      * @param number switch number between 1 and 23
  1012.      * @param value switch value
  1013.      * @return a <em>new</em> instance, with switch changed
  1014.      * @exception OrekitException if switch number is not between 1 and 23
  1015.      */
  1016.     public NRLMSISE00 withSwitch(final int number, final int value)
  1017.         throws OrekitException {
  1018.         if (number < 1 || number > 23) {
  1019.             throw new OrekitException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, number, 1, 23);
  1020.         }

  1021.         final int[] newSw       = sw.clone();
  1022.         final int[] newSwc      = swc.clone();
  1023.         if (number != 9) {
  1024.             newSw[number]  = (value == 1) ? 1 : 0;
  1025.             newSwc[number] = (value > 0) ? 1 : 0;
  1026.         } else {
  1027.             if (value == -1 || value == 1) {
  1028.                 newSw[number] = value;
  1029.             } else {
  1030.                 newSw[number] = 0;
  1031.             }
  1032.             newSwc[number] = newSw[number];
  1033.         }

  1034.         return new NRLMSISE00(inputParams, sun, earth, newSwc, newSwc);

  1035.     }

  1036.     /** Create an array of switches set to 1.
  1037.      * @return array of switches
  1038.      */
  1039.     private static int[] allOnes() {
  1040.         final int[] array = new int[24];
  1041.         Arrays.fill(array, 1);
  1042.         return array;
  1043.     }

  1044.     /** {@inheritDoc} */
  1045.     @Override
  1046.     public Frame getFrame() {
  1047.         return earth.getBodyFrame();
  1048.     }

  1049.     /** {@inheritDoc} */
  1050.     @Override
  1051.     public double getDensity(final AbsoluteDate date,
  1052.                              final Vector3D position,
  1053.                              final Frame frame)
  1054.         throws OrekitException {

  1055.         // check if data are available :
  1056.         if ((date.compareTo(inputParams.getMaxDate()) > 0) ||
  1057.             (date.compareTo(inputParams.getMinDate()) < 0)) {
  1058.             throw new OrekitException(OrekitMessages.NO_SOLAR_ACTIVITY_AT_DATE,
  1059.                                       date, inputParams.getMinDate(), inputParams.getMaxDate());
  1060.         }

  1061.         // compute day number in current year and the seconds within the day
  1062.         final DateTimeComponents dtc = date.getComponents(TimeScalesFactory.getUT1(IERSConventions.IERS_2010, true));
  1063.         final int    doy = dtc.getDate().getDayOfYear();
  1064.         final double sec = dtc.getTime().getSecondsInLocalDay();

  1065.         // compute geodetic position (km and °)
  1066.         final GeodeticPoint inBody = earth.transform(position, frame, date);
  1067.         final double alt = inBody.getAltitude() / 1000.;
  1068.         final double lon = FastMath.toDegrees(inBody.getLongitude());
  1069.         final double lat = FastMath.toDegrees(inBody.getLatitude());

  1070.         // compute local solar time
  1071.         final double lst = localSolarTime(date, position, frame);

  1072.         // get solar activity data and compute
  1073.         final Output out = new Output(doy, sec, lat, lon, lst, inputParams.getAverageFlux(date),
  1074.                                       inputParams.getDailyFlux(date), inputParams.getAp(date));
  1075.         out.gtd7d(alt);

  1076.         // return the local density
  1077.         return out.getDensity(TOTAL_MASS);

  1078.     }

  1079.     /** {@inheritDoc} */
  1080.     @Override
  1081.     public <T extends RealFieldElement<T>> T getDensity(final FieldAbsoluteDate<T> date,
  1082.                                                         final FieldVector3D<T> position,
  1083.                                                         final Frame frame)
  1084.         throws OrekitException {
  1085.         // check if data are available :
  1086.         final AbsoluteDate dateD = date.toAbsoluteDate();
  1087.         if ((dateD.compareTo(inputParams.getMaxDate()) > 0) ||
  1088.             (dateD.compareTo(inputParams.getMinDate()) < 0)) {
  1089.             throw new OrekitException(OrekitMessages.NO_SOLAR_ACTIVITY_AT_DATE,
  1090.                                       dateD, inputParams.getMinDate(), inputParams.getMaxDate());
  1091.         }

  1092.         // compute day number in current year and the seconds within the day
  1093.         final TimeScale ut1 = TimeScalesFactory.getUT1(IERSConventions.IERS_2010, true);
  1094.         final DateTimeComponents dtc = dateD.getComponents(ut1);
  1095.         final int    doy = dtc.getDate().getDayOfYear();
  1096.         final T sec = date.durationFrom(new AbsoluteDate(dtc.getDate(), TimeComponents.H00, ut1));

  1097.         // compute geodetic position (km and °)
  1098.         final FieldGeodeticPoint<T> inBody = earth.transform(position, frame, date);
  1099.         final T alt = inBody.getAltitude().divide(1000.);
  1100.         final T lon = inBody.getLongitude().multiply(180.0 / FastMath.PI);
  1101.         final T lat = inBody.getLatitude().multiply(180.0 / FastMath.PI);

  1102.         // compute local solar time
  1103.         final T lst = localSolarTime(dateD, position, frame);

  1104.         // get solar activity data and compute
  1105.         final FieldOutput<T> out = new FieldOutput<>(doy, sec, lat, lon, lst,
  1106.                                                      inputParams.getAverageFlux(dateD),
  1107.                                                      inputParams.getDailyFlux(dateD), inputParams.getAp(dateD));
  1108.         out.gtd7d(alt);

  1109.         // return the local density
  1110.         return out.getDensity(TOTAL_MASS);

  1111.     }

  1112.     /** Get local solar time.
  1113.      * @param date current date
  1114.      * @param position current position in frame
  1115.      * @param frame the frame in which is defined the position
  1116.      * @return the local solar time (hour in [0, 24[)
  1117.      * @throws OrekitException if position cannot be computed in given frame
  1118.      */
  1119.     private double localSolarTime(final AbsoluteDate date,
  1120.                                   final Vector3D position,
  1121.                                   final Frame frame) throws OrekitException {
  1122.         final Vector3D sunPos = sun.getPVCoordinates(date, frame).getPosition();
  1123.         final double lst = FastMath.PI + FastMath.atan2(
  1124.                 sunPos.getX() * position.getY() - sunPos.getY() * position.getX(),
  1125.                 sunPos.getX() * position.getX() + sunPos.getY() * position.getY());
  1126.         return lst * 12. / FastMath.PI;
  1127.     }

  1128.     /** Get local solar time.
  1129.      * @param date current date
  1130.      * @param position current position in frame
  1131.      * @param frame the frame in which is defined the position
  1132.      * @param <T> type of the filed elements
  1133.      * @return the local solar time (hour in [0, 24[)
  1134.      * @throws OrekitException if position cannot be computed in given frame
  1135.      */
  1136.     private <T extends RealFieldElement<T>> T localSolarTime(final AbsoluteDate date,
  1137.                                                              final FieldVector3D<T> position,
  1138.                                                              final Frame frame)
  1139.         throws OrekitException {
  1140.         final Vector3D sunPos = sun.getPVCoordinates(date, frame).getPosition();
  1141.         final T y  = position.getY().multiply(sunPos.getX()).subtract(position.getX().multiply(sunPos.getY()));
  1142.         final T x  = position.getX().multiply(sunPos.getX()).add(position.getY().multiply(sunPos.getY()));
  1143.         final T hl = y.atan2(x).add(FastMath.PI);

  1144.         return hl.multiply(12. / FastMath.PI);

  1145.     }

  1146.     /**
  1147.      * This class is a placeholder for the computed densities and temperatures.
  1148.      * <p>
  1149.      * Densities are provided as an array d such as:
  1150.      * <ul>
  1151.      * <li>d[0] = He number density (1/m³)</li>
  1152.      * <li>d[1] = O number density (1/m³)</li>
  1153.      * <li>d[2] = N2 number density (1/m³)</li>
  1154.      * <li>d[3] = O2 number density (1/m³)</li>
  1155.      * <li>d[4] = Ar number density (1/m³)</li>
  1156.      * <li>d[5] = total mass density (kg/m³) (*)</li>
  1157.      * <li>d[6] = H number density (1/m³)</li>
  1158.      * <li>d[7] = N number density (1/m³)</li>
  1159.      * <li>d[8] = anomalous oxygen number density (1/m³)
  1160.      * </ul>
  1161.      * Total mass density, d[5], is NOT the same for methods gtd7 and gtd7d:
  1162.      * <ul>
  1163.      * <li>For gtd7: d[5] is the sum of the mass densities of the species
  1164.      * He, O, N2, O2, Ar, H and N but does NOT include anomalous oxygen.</li>
  1165.      * <li>For gtd7d: d[5] is the "effective total mass density for drag" and is the sum
  1166.      * of the mass densities of all species in this model, INCLUDING anomalous oxygen.</li>
  1167.      * </ul>
  1168.      * O, H, and N are set to zero below 72.5 km.
  1169.      * </p>
  1170.      * <p>
  1171.      * Temperatures are provided as an array t such as:
  1172.      * <ul>
  1173.      * <li>t[0] = exospheric temperature (K)</li>
  1174.      * <li>t[1] = temperature at altitude (K)</li>
  1175.      * </ul>
  1176.      * t[0] is set to global average for altitudes below 120 km.<br>
  1177.      * The 120 km gradient is left at global average value for altitudes below 72 km.
  1178.      * </p>
  1179.      */
  1180.     private class Output {

  1181.         /** Day of year (from 1 to 365 or 366). */
  1182.         private final int doy;

  1183.         /** Seconds in day (UT scale). */
  1184.         private final double sec;

  1185.         /** Geodetic latitude (°). */
  1186.         private final double lat;

  1187.         /** Geodetic longitude (°). */
  1188.         private final double lon;

  1189.         /** Local apparent solar time (hours). */
  1190.         private final double hl;

  1191.         /** 81 day average of F10.7 flux (centered on day). */
  1192.         private final double f107a;

  1193.         /** Daily F10.7 flux for previous day. */
  1194.         private final double f107;

  1195.         /** Array containing:
  1196.         *  <ul>
  1197.         *  <li>0: daily Ap</li>
  1198.         *  <li>1: 3 hr ap index for current time</li>
  1199.         *  <li>2: 3 hr ap index for 3 hrs before current time</li>
  1200.         *  <li>3: 3 hr ap index for 6 hrs before current time</li>
  1201.         *  <li>4: 3 hr ap index for FOR 9 hrs before current time</li>
  1202.         *  <li>5: average of eight 3 hr ap indices from 12 to 33 hrs prior to current time</li>
  1203.         *  <li>6: average of eight 3 hr ap indices from 36 to 57 hrs prior to current time</li>
  1204.         *  </ul>. */
  1205.         private final double[] ap;

  1206.         /** Gravity at latitude (cm/s2). */
  1207.         private final double glat;

  1208.         /** Effective Earth radius at latitude (km). */
  1209.         private final double rlat;

  1210.         /** N2 mixed density at alt. */
  1211.         private double dm28;

  1212.         /** Legendre polynomials. */
  1213.         private final double[][] plg;

  1214.         /** Cosinus of local solar time. */
  1215.         private final double ctloc;
  1216.         /** Sinus of local solar time. */
  1217.         private final double stloc;
  1218.         /** Square of ctloc. */
  1219.         private final double c2tloc;
  1220.         /** Square of stloc. */
  1221.         private final double s2tloc;
  1222.         /** Cube of ctloc. */
  1223.         private final double c3tloc;
  1224.         /** Cube of stloc. */
  1225.         private final double s3tloc;

  1226.         /** Magnetic activity based on daily ap. */
  1227.         private double apdf;

  1228.         /** Magnetic activity based on daily ap. */
  1229.         private double apt;

  1230.         /** Temperature at nodes for ZN1 scale. */
  1231.         private final double[] meso_tn1;

  1232.         /** Temperature at nodes for ZN2 scale. */
  1233.         private final double[] meso_tn2;

  1234.         /** Temperature at nodes for ZN3 scale. */
  1235.         private final double[] meso_tn3;

  1236.         /** Temperature gradients at end nodes for ZN1 scale. */
  1237.         private final double[] meso_tgn1;

  1238.         /** Temperature gradients at end nodes for ZN2 scale. */
  1239.         private final double[] meso_tgn2;

  1240.         /** Temperature gradients at end nodes for ZN3 scale. */
  1241.         private final double[] meso_tgn3;

  1242.         /** Densities. */
  1243.         private final double[] densities;

  1244.         /** Temperatures. */
  1245.         private final double[] temperatures;

  1246.         /** Simple constructor.
  1247.          *  @param doy day of year (from 1 to 365 or 366)
  1248.          *  @param sec seconds in day (UT scale)
  1249.          *  @param lat geodetic latitude (°)
  1250.          *  @param lon geodetic longitude (°)
  1251.          *  @param hl local apparent solar time (hours)
  1252.          *  @param f107a 81 day average of F10.7 flux (centered on day)
  1253.          *  @param f107 daily F10.7 flux for previous day
  1254.          *  @param ap array containing:
  1255.          *  <ul>
  1256.          *  <li>0: daily Ap</li>
  1257.          *  <li>1: 3 hr ap index for current time</li>
  1258.          *  <li>2: 3 hr ap index for 3 hrs before current time</li>
  1259.          *  <li>3: 3 hr ap index for 6 hrs before current time</li>
  1260.          *  <li>4: 3 hr ap index for FOR 9 hrs before current time</li>
  1261.          *  <li>5: average of eight 3 hr ap indices from 12 to 33 hrs prior to current time</li>
  1262.          *  <li>6: average of eight 3 hr ap indices from 36 to 57 hrs prior to current time</li>
  1263.          *  </ul>
  1264.          */
  1265.         Output(final int doy, final double sec,
  1266.                final double lat, final double lon, final double hl,
  1267.                final double f107a, final double f107, final double[] ap) {

  1268.             this.doy   = doy;
  1269.             this.sec   = sec;
  1270.             this.lat   = lat;
  1271.             this.lon   = lon;
  1272.             this.hl    = hl;
  1273.             this.f107a = f107a;
  1274.             this.f107  = f107;
  1275.             this.ap    = ap.clone();

  1276.             this.plg       = new double[4][8];

  1277.             this.meso_tn1  = new double[ZN1.length];
  1278.             this.meso_tn2  = new double[ZN2.length];
  1279.             this.meso_tn3  = new double[ZN3.length];
  1280.             this.meso_tgn1 = new double[2];
  1281.             this.meso_tgn2 = new double[2];
  1282.             this.meso_tgn3 = new double[2];

  1283.             densities       = new double[9];
  1284.             temperatures    = new double[2];

  1285.             // Calculates latitude variable gravity and effective radius
  1286.             final double xlat = (sw[2] == 0) ? LAT_REF : lat;
  1287.             final double c2   = FastMath.cos(2 * DEG_TO_RAD * xlat);
  1288.             glat = G_REF * (1. - .0026373 * c2);
  1289.             rlat = 2. * glat / (3.085462e-6 + 2.27e-9 * c2) * 1.e-5;

  1290.             // Convert latitude into radians
  1291.             final double latr = DEG_TO_RAD * lat;

  1292.             // Calculate legendre polynomials
  1293.             final double c = FastMath.sin(latr);
  1294.             final double s = FastMath.cos(latr);

  1295.             plg[0][1] = c;
  1296.             plg[0][2] = ( 3.0 * c * plg[0][1] - 1.0) / 2.0;
  1297.             plg[0][3] = ( 5.0 * c * plg[0][2] - 2.0 * plg[0][1]) / 3.0;
  1298.             plg[0][4] = ( 7.0 * c * plg[0][3] - 3.0 * plg[0][2]) / 4.0;
  1299.             plg[0][5] = ( 9.0 * c * plg[0][4] - 4.0 * plg[0][3]) / 5.0;
  1300.             plg[0][6] = (11.0 * c * plg[0][5] - 5.0 * plg[0][4]) / 6.0;

  1301.             plg[1][1] = s;
  1302.             plg[1][2] =   3.0 * c * plg[1][1];
  1303.             plg[1][3] = ( 5.0 * c * plg[1][2] - 3.0 * plg[1][1]) / 2.0;
  1304.             plg[1][4] = ( 7.0 * c * plg[1][3] - 4.0 * plg[1][2]) / 3.0;
  1305.             plg[1][5] = ( 9.0 * c * plg[1][4] - 5.0 * plg[1][3]) / 4.0;
  1306.             plg[1][6] = (11.0 * c * plg[1][5] - 6.0 * plg[1][4]) / 5.0;

  1307.             plg[2][2] = 3.0 * s * plg[1][1];
  1308.             plg[2][3] =   5.0 * c * plg[2][2];
  1309.             plg[2][4] = ( 7.0 * c * plg[2][3] - 5.0 * plg[2][2]) / 2.0;
  1310.             plg[2][5] = ( 9.0 * c * plg[2][4] - 6.0 * plg[2][3]) / 3.0;
  1311.             plg[2][6] = (11.0 * c * plg[2][5] - 7.0 * plg[2][4]) / 4.0;
  1312.             plg[2][7] = (13.0 * c * plg[2][6] - 8.0 * plg[2][5]) / 5.0;

  1313.             plg[3][3] = 5.0 * s * plg[2][2];
  1314.             plg[3][4] =   7.0 * c * plg[3][3];
  1315.             plg[3][5] = ( 9.0 * c * plg[3][4] - 7.0 * plg[3][3]) / 2.0;
  1316.             plg[3][6] = (11.0 * c * plg[3][5] - 8.0 * plg[3][4]) / 3.0;

  1317.             // Calculate additional data
  1318.             if (!(sw[7] == 0 && sw[8] == 0 && sw[14] == 0)) {
  1319.                 final double tloc = HOUR_TO_RAD * hl;
  1320.                 final double tlx2 = tloc + tloc;
  1321.                 final double tlx3 = tloc + tlx2;
  1322.                 stloc  = FastMath.sin(tloc);
  1323.                 ctloc  = FastMath.cos(tloc);
  1324.                 s2tloc = FastMath.sin(tlx2);
  1325.                 c2tloc = FastMath.cos(tlx2);
  1326.                 s3tloc = FastMath.sin(tlx3);
  1327.                 c3tloc = FastMath.cos(tlx3);
  1328.             } else {
  1329.                 stloc  = 0;
  1330.                 ctloc  = 0;
  1331.                 s2tloc = 0;
  1332.                 c2tloc = 0;
  1333.                 s3tloc = 0;
  1334.                 c3tloc = 0;
  1335.             }

  1336.         }

  1337.         /** Calculate temperatures and densities not including anomalous oxygen.
  1338.          *  <p>
  1339.          *  This method is the thermospheric portion of NRLMSISE-00 for alt > 72.5 km.
  1340.          *  </p>
  1341.          *  <p>NOTES ON INPUT VARIABLES:<br>
  1342.          *  Seconds, Local Time, and Longitude are used independently in the
  1343.          *  model and are not of equal importance for every situation.<br>
  1344.          *  For the most physically realistic calculation these three
  1345.          *  variables should be consistent (lst=sec/3600 + lon/15).<br>
  1346.          *  The Equation of Time departures from the above formula
  1347.          *  for apparent local time can be included if available but
  1348.          *  are of minor importance.<br><br>
  1349.          *
  1350.          *  f107 and f107A values used to generate the model correspond
  1351.          *  to the 10.7 cm radio flux at the actual distance of the Earth
  1352.          *  from the Sun rather than the radio flux at 1 AU. The following
  1353.          *  site provides both classes of values:<br>
  1354.          *  ftp://ftp.ngdc.noaa.gov/STP/SOLAR_DATA/SOLAR_RADIO/FLUX/<br><br>
  1355.          *
  1356.          *  f107, f107A, and ap effects are neither large nor well established below 80 km
  1357.          *  and these parameters should be set to 150., 150., and 4. respectively.
  1358.          *  </p>
  1359.          *  @param alt altitude (km)
  1360.          */
  1361.         void gts7(final double alt) {

  1362.             // Thermal diffusion coefficients for species
  1363.             final double[] alpha = {-0.38, 0.0, 0.0, 0.0, 0.17, 0.0, -0.38, 0.0, 0.0};
  1364.             // Altitude limits for net density computation for species
  1365.             final double[] altl  = {200.0, 300.0, 160.0, 250.0, 240.0, 450.0, 320.0, 450.0};
  1366.             // N2 mixed density
  1367.             final double xmm = PDM[2][4];

  1368.             /**** Exospheric temperature ****/
  1369.             double tinf = PTM[0] * PT[0];
  1370.             // Tinf variations not important below ZA or ZN[0]
  1371.             if (alt > ZN1[0]) {
  1372.                 tinf *= 1.0 + sw[16] * globe7(PT);
  1373.             }
  1374.             setTemperature(EXOSPHERIC, tinf);

  1375.             // Gradient variations not important below ZN[4]
  1376.             double g0 = PTM[3] * PS[0];
  1377.             if (alt > ZN1[4]) {
  1378.                 g0 *= 1.0 + sw[19] * globe7(PS);
  1379.             }

  1380.             // Temperature at lower boundary
  1381.             double tlb = PTM[1] * PD[3][0];
  1382.             tlb *= 1.0 + sw[17] * globe7(PD[3]);

  1383.             // Slope
  1384.             final double s = g0 / (tinf - tlb);

  1385.             // Lower thermosphere temp variations not significant for density above 300 km
  1386.             meso_tn1[1]  = PTM[6] * PTL[0][0];
  1387.             meso_tn1[2]  = PTM[2] * PTL[1][0];
  1388.             meso_tn1[3]  = PTM[7] * PTL[2][0];
  1389.             meso_tn1[4]  = PTM[4] * PTL[3][0];
  1390.             meso_tgn1[1] = PTM[8] * PMA[8][0];
  1391.             if (alt < 300.0) {
  1392.                 final double r = PTM[4] * PTL[3][0];
  1393.                 meso_tn1[1]  /= 1.0 - sw[18] * glob7s(PTL[0]);
  1394.                 meso_tn1[2]  /= 1.0 - sw[18] * glob7s(PTL[1]);
  1395.                 meso_tn1[3]  /= 1.0 - sw[18] * glob7s(PTL[2]);
  1396.                 meso_tn1[4]  /= 1.0 - sw[18] * sw[20] * glob7s(PTL[3]);
  1397.                 meso_tgn1[1] *= 1.0 + sw[18] * sw[20] * glob7s(PMA[8]);
  1398.                 meso_tgn1[1] *= meso_tn1[4] * meso_tn1[4] / (r * r);
  1399.             }

  1400.             /**** Temperature at altitude ****/
  1401.             setTemperature(ALTITUDE, densu(alt, 1.0, tinf, tlb, 0.0, 0.0, PTM[5], s));

  1402.             /**** N2 density ****/
  1403.             /*   Density variation factor at Zlb */
  1404.             final double g28 = sw[21] * globe7(PD[2]);
  1405.             /* Diffusive density at Zlb */
  1406.             final double db28 = PDM[2][0] * FastMath.exp(g28) * PD[2][0];
  1407.             /* Diffusive density at Alt */
  1408.             double diffusiveDensity = densu(alt, db28, tinf, tlb, N2_MASS, alpha[2], PTM[5], s);
  1409.             setDensity(MOLECULAR_NITROGEN, diffusiveDensity);
  1410.             // Variation of turbopause height
  1411.             final double zhf = PDL[1][24] * (1.0 + sw[5] * PDL[0][24] *
  1412.                                        FastMath.sin(DEG_TO_RAD * lat) *
  1413.                                        FastMath.cos(DAY_TO_RAD * (doy - PT[13])));
  1414.             /* Turbopause */
  1415.             final double zh28  = PDM[2][2] * zhf;
  1416.             final double zhm28 = PDM[2][3] * PDL[1][5];
  1417.             /* Mixed density at Zlb */
  1418.             final double b28 = densu(zh28, db28, tinf, tlb, N2_MASS - xmm, alpha[2] - 1.0, PTM[5], s);
  1419.             if (sw[15] != 0 && alt <= altl[2]) {
  1420.                 /*  Mixed density at Alt */
  1421.                 dm28 = densu(alt, b28, tinf, tlb, xmm, alpha[2], PTM[5], s);
  1422.                 /*  Net density at Alt */
  1423.                 setDensity(MOLECULAR_NITROGEN, dnet(diffusiveDensity, dm28, zhm28, xmm, N2_MASS));
  1424.             }

  1425.             /**** He density ****/
  1426.             /*   Density variation factor at Zlb */
  1427.             final double g4 = sw[21] * globe7(PD[0]);
  1428.             /*  Diffusive density at Zlb */
  1429.             final double db04 = PDM[0][0] * FastMath.exp(g4) * PD[0][0];
  1430.             /*  Diffusive density at Alt */
  1431.             diffusiveDensity = densu(alt, db04, tinf, tlb, HE_MASS, alpha[0], PTM[5], s);
  1432.             setDensity(HELIUM, diffusiveDensity);
  1433.             if (sw[15] != 0 && alt < altl[0]) {
  1434.                 /*  Turbopause */
  1435.                 final double zh04 = PDM[0][2];
  1436.                 /*  Mixed density at Zlb */
  1437.                 final double b04 = densu(zh04, db04, tinf, tlb, HE_MASS - xmm, alpha[0] - 1., PTM[5], s);
  1438.                 /*  Mixed density at Alt */
  1439.                 final double dm04 = densu(alt, b04, tinf, tlb, xmm, 0., PTM[5], s);
  1440.                 final double zhm04 = zhm28;
  1441.                 /*  Net density at Alt */
  1442.                 diffusiveDensity = dnet(diffusiveDensity, dm04, zhm04, xmm, HE_MASS);
  1443.                 /*  Correction to specified mixing ratio at ground */
  1444.                 final double rl = FastMath.log(b28 * PDM[0][1] / b04);
  1445.                 final double zc04 = PDM[0][4] * PDL[1][0];
  1446.                 final double hc04 = PDM[0][5] * PDL[1][1];
  1447.                 /*  Net density corrected at Alt */
  1448.                 setDensity(HELIUM, diffusiveDensity * ccor(alt, rl, hc04, zc04));
  1449.             }

  1450.             /**** O density ****/
  1451.             /* Density variation factor at Zlb */
  1452.             final double g16 = sw[21] * globe7(PD[1]);
  1453.             /* Diffusive density at Zlb */
  1454.             final double db16 = PDM[1][0] * FastMath.exp(g16) * PD[1][0];
  1455.             /* Diffusive density at Alt */
  1456.             diffusiveDensity = densu(alt, db16, tinf, tlb, O_MASS, alpha[1], PTM[5], s);
  1457.             setDensity(ATOMIC_OXYGEN, diffusiveDensity);
  1458.             if (sw[15] != 0 && alt < altl[1]) {
  1459.                 /* Turbopause */
  1460.                 final double zh16 = PDM[1][2];
  1461.                 /* Mixed density at Zlb */
  1462.                 final double b16 = densu(zh16, db16, tinf, tlb, O_MASS - xmm, alpha[1] - 1.0, PTM[5], s);
  1463.                 /* Mixed density at Alt */
  1464.                 final double dm16 = densu(alt, b16, tinf, tlb, xmm, 0., PTM[5], s);
  1465.                 final double zhm16 = zhm28;
  1466.                 /* Net density at Alt */
  1467.                 diffusiveDensity = dnet(diffusiveDensity, dm16, zhm16, xmm, O_MASS);
  1468.                 final double rl = PDM[1][1] * PDL[1][16] * (1.0 + sw[1] * PDL[0][23] * (f107a - FLUX_REF));
  1469.                 final double hc16 = PDM[1][5] * PDL[1][3];
  1470.                 final double zc16 = PDM[1][4] * PDL[1][2];
  1471.                 final double hc216 = PDM[1][5] * PDL[1][4];
  1472.                 diffusiveDensity *= ccor2(alt, rl, hc16, zc16, hc216);
  1473.                 /* Chemistry correction */
  1474.                 final double hcc16 = PDM[1][7] * PDL[1][13];
  1475.                 final double zcc16 = PDM[1][6] * PDL[1][12];
  1476.                 final double rc16  = PDM[1][3] * PDL[1][14];
  1477.                 /* Net density corrected at Alt */
  1478.                 setDensity(ATOMIC_OXYGEN, diffusiveDensity * ccor(alt, rc16, hcc16, zcc16));
  1479.             }

  1480.             /**** O2 density ****/
  1481.             /* Density variation factor at Zlb */
  1482.             final double g32 = sw[21] * globe7(PD[4]);
  1483.             /* Diffusive density at Zlb */
  1484.             final double db32 = PDM[3][0] * FastMath.exp(g32) * PD[4][0];
  1485.             /* Diffusive density at Alt */
  1486.             diffusiveDensity = densu(alt, db32, tinf, tlb, O2_MASS, alpha[3], PTM[5], s);
  1487.             setDensity(MOLECULAR_OXYGEN, diffusiveDensity);
  1488.             if (sw[15] != 0) {
  1489.                 if (alt <= altl[3]) {
  1490.                     /* Turbopause */
  1491.                     final double zh32 = PDM[3][2];
  1492.                     /* Mixed density at Zlb */
  1493.                     final double b32 = densu(zh32, db32, tinf, tlb, O2_MASS - xmm, alpha[3] - 1., PTM[5], s);
  1494.                     /* Mixed density at Alt */
  1495.                     final double dm32 = densu(alt, b32, tinf, tlb, xmm, 0., PTM[5], s);
  1496.                     final double zhm32 = zhm28;
  1497.                     /* Net density at Alt */
  1498.                     diffusiveDensity = dnet(diffusiveDensity, dm32, zhm32, xmm, O2_MASS);
  1499.                     /* Correction to specified mixing ratio at ground */
  1500.                     final double rl = FastMath.log(b28 * PDM[3][1] / b32);
  1501.                     final double hc32 = PDM[3][5] * PDL[1][7];
  1502.                     final double zc32 = PDM[3][4] * PDL[1][6];
  1503.                     diffusiveDensity *= ccor(alt, rl, hc32, zc32);
  1504.                 }
  1505.                 /* Correction for general departure from diffusive equilibrium above Zlb */
  1506.                 final double hcc32  = PDM[3][7] * PDL[1][22];
  1507.                 final double hcc232 = PDM[3][7] * PDL[0][22];
  1508.                 final double zcc32  = PDM[3][6] * PDL[1][21];
  1509.                 final double rc32   = PDM[3][3] * PDL[1][23] * (1. + sw[1] * PDL[0][23] * (f107a - FLUX_REF));
  1510.                 /* Net density corrected at Alt */
  1511.                 setDensity(MOLECULAR_OXYGEN, diffusiveDensity * ccor2(alt, rc32, hcc32, zcc32, hcc232));
  1512.             }

  1513.             /**** Ar density ****/
  1514.             /* Density variation factor at Zlb */
  1515.             final double g40 = sw[21] * globe7(PD[5]);
  1516.             /* Diffusive density at Zlb */
  1517.             final double db40 = PDM[4][0] * FastMath.exp(g40) * PD[5][0];
  1518.             /* Diffusive density at Alt */
  1519.             diffusiveDensity = densu(alt, db40, tinf, tlb, AR_MASS, alpha[4], PTM[5], s);
  1520.             setDensity(ARGON, diffusiveDensity);
  1521.             if (sw[15] != 0 && alt <= altl[4]) {
  1522.                 /* Turbopause */
  1523.                 final double zh40 = PDM[4][2];
  1524.                 /* Mixed density at Zlb */
  1525.                 final double b40 = densu(zh40, db40, tinf, tlb, AR_MASS - xmm, alpha[4] - 1., PTM[5], s);
  1526.                 /* Mixed density at Alt */
  1527.                 final double dm40 = densu(alt, b40, tinf, tlb, xmm, 0., PTM[5], s);
  1528.                 final double zhm40 = zhm28;
  1529.                 /* Net density at Alt */
  1530.                 diffusiveDensity = dnet(diffusiveDensity, dm40, zhm40, xmm, AR_MASS);
  1531.                 /* Correction to specified mixing ratio at ground */
  1532.                 final double rl = FastMath.log(b28 * PDM[4][1] / b40);
  1533.                 final double hc40 = PDM[4][5] * PDL[1][9];
  1534.                 final double zc40 = PDM[4][4] * PDL[1][8];
  1535.                 /* Net density corrected at Alt */
  1536.                 setDensity(ARGON, diffusiveDensity * ccor(alt, rl, hc40, zc40));
  1537.             }

  1538.             /**** H density ****/
  1539.             /* Density variation factor at Zlb */
  1540.             final double g1 = sw[21] * globe7(PD[6]);
  1541.             /* Diffusive density at Zlb */
  1542.             final double db01 = PDM[5][0] * FastMath.exp(g1) * PD[6][0];
  1543.             /* Diffusive density at Alt */
  1544.             diffusiveDensity = densu(alt, db01, tinf, tlb, H_MASS, alpha[6], PTM[5], s);
  1545.             setDensity(HYDROGEN, diffusiveDensity);
  1546.             if (sw[15] != 0 && alt <= altl[6]) {
  1547.                 /* Turbopause */
  1548.                 final double zh01 = PDM[5][2];
  1549.                 /* Mixed density at Zlb */
  1550.                 final double b01 = densu(zh01, db01, tinf, tlb, H_MASS - xmm, alpha[6] - 1., PTM[5], s);
  1551.                 /* Mixed density at Alt */
  1552.                 final double dm01 = densu(alt, b01, tinf, tlb, xmm, 0., PTM[5], s);
  1553.                 final double zhm01 = zhm28;
  1554.                 /* Net density at Alt */
  1555.                 diffusiveDensity = dnet(diffusiveDensity, dm01, zhm01, xmm, H_MASS);
  1556.                 /* Correction to specified mixing ratio at ground */
  1557.                 final double rl = FastMath.log(b28 * PDM[5][1] * FastMath.sqrt(PDL[1][17] * PDL[1][17]) / b01);
  1558.                 final double hc01 = PDM[5][5] * PDL[1][11];
  1559.                 final double zc01 = PDM[5][4] * PDL[1][10];
  1560.                 diffusiveDensity *= ccor(alt, rl, hc01, zc01);
  1561.                 /* Chemistry correction */
  1562.                 final double hcc01 = PDM[5][7] * PDL[1][19];
  1563.                 final double zcc01 = PDM[5][6] * PDL[1][18];
  1564.                 final double rc01 = PDM[5][3] * PDL[1][20];
  1565.                 /* Net density corrected at Alt */
  1566.                 setDensity(HYDROGEN, diffusiveDensity * ccor(alt, rc01, hcc01, zcc01));
  1567.             }

  1568.             /**** N density ****/
  1569.             /* Density variation factor at Zlb */
  1570.             final double g14 = sw[21] * globe7(PD[7]);
  1571.             /* Diffusive density at Zlb */
  1572.             final double db14 = PDM[6][0] * FastMath.exp(g14) * PD[7][0];
  1573.             /* Diffusive density at Alt */
  1574.             diffusiveDensity = densu(alt, db14, tinf, tlb, N_MASS, alpha[7], PTM[5], s);
  1575.             setDensity(ATOMIC_NITROGEN, diffusiveDensity);
  1576.             if (sw[15] != 0 && alt <= altl[7]) {
  1577.                 /* Turbopause */
  1578.                 final double zh14 = PDM[6][2];
  1579.                 /* Mixed density at Zlb */
  1580.                 final double b14 = densu(zh14, db14, tinf, tlb, N_MASS - xmm, alpha[7] - 1., PTM[5], s);
  1581.                 /* Mixed density at Alt */
  1582.                 final double dm14 = densu(alt, b14, tinf, tlb, xmm, 0., PTM[5], s);
  1583.                 final double zhm14 = zhm28;
  1584.                 /* Net density at Alt */
  1585.                 diffusiveDensity = dnet(diffusiveDensity, dm14, zhm14, xmm, N_MASS);
  1586.                 /* Correction to specified mixing ratio at ground */
  1587.                 final double rl = FastMath.log(b28 * PDM[6][1] * PDL[0][2] / b14);
  1588.                 final double hc14 = PDM[6][5] * PDL[0][1];
  1589.                 final double zc14 = PDM[6][4] * PDL[0][0];
  1590.                 diffusiveDensity *= ccor(alt, rl, hc14, zc14);
  1591.                 /* Chemistry correction */
  1592.                 final double hcc14 = PDM[6][7] * PDL[0][4];
  1593.                 final double zcc14 = PDM[6][6] * PDL[0][3];
  1594.                 final double rc14 = PDM[6][3] * PDL[0][5];
  1595.                 /* Net density corrected at Alt */
  1596.                 setDensity(ATOMIC_NITROGEN, diffusiveDensity * ccor(alt, rc14, hcc14, zcc14));
  1597.             }

  1598.             /**** Anomalous O density ****/
  1599.             final double g16h  = sw[21] * globe7(PD[8]);
  1600.             final double db16h = PDM[7][0] * FastMath.exp(g16h) * PD[8][0];
  1601.             final double tho   = PDM[7][9] * PDL[0][6];
  1602.             diffusiveDensity = densu(alt, db16h, tho, tho, O_MASS, alpha[8], PTM[5], s);
  1603.             final double zsht = PDM[7][5];
  1604.             final double zmho = PDM[7][4];
  1605.             final double zsho = scalh(zmho, O_MASS, tho);
  1606.             diffusiveDensity *= FastMath.exp(-zsht / zsho * (FastMath.exp((zmho - alt ) / zsht) - 1.));
  1607.             setDensity(ANOMALOUS_OXYGEN, diffusiveDensity);

  1608.             // Convert densities from cm-3 to m-3
  1609.             for (int i = 0; i < 9; i++) {
  1610.                 setDensity(i, getDensity(i) * 1.0e+06);
  1611.             }

  1612.             /**** Total mass density ****/
  1613.             final double tmd = AMU * (HE_MASS * getDensity(HELIUM) +
  1614.                                       O_MASS  * getDensity(ATOMIC_OXYGEN) +
  1615.                                       N2_MASS * getDensity(MOLECULAR_NITROGEN) +
  1616.                                       O2_MASS * getDensity(MOLECULAR_OXYGEN) +
  1617.                                       AR_MASS * getDensity(ARGON) +
  1618.                                       H_MASS  * getDensity(HYDROGEN) +
  1619.                                       N_MASS  * getDensity(ATOMIC_NITROGEN));
  1620.             setDensity(TOTAL_MASS, tmd);

  1621.         }

  1622.         /** Calculate temperatures and densities not including anomalous oxygen.
  1623.          *  <p>NOTES ON INPUT VARIABLES:<br>
  1624.          *  Seconds, Local Time, and Longitude are used independently in the
  1625.          *  model and are not of equal importance for every situation.<br>
  1626.          *  For the most physically realistic calculation these three
  1627.          *  variables should be consistent (lst=sec/3600 + lon/15).<br>
  1628.          *  The Equation of Time departures from the above formula
  1629.          *  for apparent local time can be included if available but
  1630.          *  are of minor importance.<br><br>
  1631.          *
  1632.          *  f107 and f107A values used to generate the model correspond
  1633.          *  to the 10.7 cm radio flux at the actual distance of the Earth
  1634.          *  from the Sun rather than the radio flux at 1 AU. The following
  1635.          *  site provides both classes of values:<br>
  1636.          *  ftp://ftp.ngdc.noaa.gov/STP/SOLAR_DATA/SOLAR_RADIO/FLUX/<br><br>
  1637.          *
  1638.          *  f107, f107A, and ap effects are neither large nor well established below 80 km
  1639.          *  and these parameters should be set to 150., 150., and 4. respectively.
  1640.          *  </p>
  1641.          *  @param alt altitude (km)
  1642.          */
  1643.         void gtd7(final double alt) {

  1644.             // Calculates for thermosphere/mesosphere (above ZN2[0])
  1645.             final double altt = (alt > ZN2[0]) ? alt : ZN2[0];
  1646.             gts7(altt);
  1647.             if (alt >= ZN2[0]) {
  1648.                 return;
  1649.             }

  1650.             // Calculates for lower mesosphere/upper stratosphere (between ZN2[0] and ZN3[0]):
  1651.             // Temperature at nodes and gradients at end nodes
  1652.             // Inverse temperature a linear function of spherical harmonics
  1653.             final double r = PMA[2][0] * PAVGM[2];
  1654.             meso_tgn2[0] = meso_tgn1[1];
  1655.             meso_tn2[0]  = meso_tn1[4];
  1656.             meso_tn2[1]  = PMA[0][0] * PAVGM[0] / (1.0 - sw[20] * glob7s(PMA[0]));
  1657.             meso_tn2[2]  = PMA[1][0] * PAVGM[1] / (1.0 - sw[20] * glob7s(PMA[1]));
  1658.             meso_tn2[3]  = PMA[2][0] * PAVGM[2] / (1.0 - sw[20] * sw[22] * glob7s(PMA[2]));
  1659.             meso_tgn2[1] = PMA[9][0] * PAVGM[8] * (1.0 + sw[20] * sw[22] * glob7s(PMA[9])) *
  1660.                            meso_tn2[3] * meso_tn2[3] / (r * r);
  1661.             meso_tn3[0]  = meso_tn2[3];

  1662.             // Calculates for lower stratosphere and troposphere (below ZN3[0])
  1663.             // Temperature at nodes and gradients at end nodes
  1664.             // Inverse temperature a linear function of spherical harmonics
  1665.             if (alt < ZN3[0]) {
  1666.                 final double q = PMA[6][0] * PAVGM[6];
  1667.                 meso_tgn3[0] = meso_tgn2[1];
  1668.                 meso_tn3[1]  = PMA[3][0] * PAVGM[3] / (1.0 - sw[22] * glob7s(PMA[3]));
  1669.                 meso_tn3[2]  = PMA[4][0] * PAVGM[4] / (1.0 - sw[22] * glob7s(PMA[4]));
  1670.                 meso_tn3[3]  = PMA[5][0] * PAVGM[5] / (1.0 - sw[22] * glob7s(PMA[5]));
  1671.                 meso_tn3[4]  = PMA[6][0] * PAVGM[6] / (1.0 - sw[22] * glob7s(PMA[6]));
  1672.                 meso_tgn3[1] = PMA[7][0] * PAVGM[7] * (1.0 + sw[22] * glob7s(PMA[7])) *
  1673.                                meso_tn3[4] * meso_tn3[4] / (q * q);

  1674.             }

  1675.             // Linear transition to full mixing below ZN2[0]
  1676.             final double dmc = (alt > ZMIX) ? 1.0 - (ZN2[0] - alt) / (ZN2[0] - ZMIX) : 0.;
  1677.             final double dz28 = getDensity(MOLECULAR_NITROGEN);

  1678.             // N2 density
  1679.             final double dm28m = dm28 * 1.0e+06;
  1680.             double dmr = dz28 / dm28m - 1.0;
  1681.             double dst = densm(alt, dm28m, PDM[2][4]) * (1.0 + dmr * dmc);
  1682.             setDensity(MOLECULAR_NITROGEN, dst);

  1683.             // HE density
  1684.             dmr = getDensity(HELIUM) / (dz28 * PDM[0][1]) - 1.0;
  1685.             dst = getDensity(MOLECULAR_NITROGEN) * PDM[0][1] * (1.0 + dmr * dmc);
  1686.             setDensity(HELIUM, dst);

  1687.             // O density
  1688.             setDensity(ATOMIC_OXYGEN, 0.);
  1689.             setDensity(ANOMALOUS_OXYGEN, 0.);

  1690.             // O2 density
  1691.             dmr = getDensity(MOLECULAR_OXYGEN) / (dz28 * PDM[3][1]) - 1.0;
  1692.             dst = getDensity(MOLECULAR_NITROGEN) * PDM[3][1] * (1.0 + dmr * dmc);
  1693.             setDensity(MOLECULAR_OXYGEN, dst);

  1694.             // AR density
  1695.             dmr = getDensity(ARGON) / (dz28 * PDM[4][1]) - 1.0;
  1696.             dst = getDensity(MOLECULAR_NITROGEN) * PDM[4][1] * (1.0 + dmr * dmc);
  1697.             setDensity(ARGON, dst);

  1698.             // H density
  1699.             setDensity(HYDROGEN, 0.);

  1700.             // N density
  1701.             setDensity(ATOMIC_NITROGEN, 0.);

  1702.             // Total mass density
  1703.             final double tmd = AMU * (HE_MASS * getDensity(HELIUM) +
  1704.                                       O_MASS  * getDensity(ATOMIC_OXYGEN) +
  1705.                                       N2_MASS * getDensity(MOLECULAR_NITROGEN) +
  1706.                                       O2_MASS * getDensity(MOLECULAR_OXYGEN) +
  1707.                                       AR_MASS * getDensity(ARGON) +
  1708.                                       H_MASS  * getDensity(HYDROGEN) +
  1709.                                       N_MASS  * getDensity(ATOMIC_NITROGEN));
  1710.             setDensity(TOTAL_MASS, tmd);

  1711.             // Temperature at altitude
  1712.             setTemperature(ALTITUDE, densm(alt, 1.0, 0));

  1713.         }

  1714.         /** Calculate temperatures and densities including anomalous oxygen.
  1715.          *  <p></p>
  1716.          *  <p>NOTES ON INPUT VARIABLES:<br>
  1717.          *  Seconds, Local Time, and Longitude are used independently in the
  1718.          *  model and are not of equal importance for every situation.<br>
  1719.          *  For the most physically realistic calculation these three
  1720.          *  variables should be consistent (lst=sec/3600 + lon/15).<br>
  1721.          *  The Equation of Time departures from the above formula
  1722.          *  for apparent local time can be included if available but
  1723.          *  are of minor importance.<br>
  1724.          *  <br>
  1725.          *  f107 and f107A values used to generate the model correspond
  1726.          *  to the 10.7 cm radio flux at the actual distance of the Earth
  1727.          *  from the Sun rather than the radio flux at 1 AU. The following
  1728.          *  site provides both classes of values:<br>
  1729.          *  ftp://ftp.ngdc.noaa.gov/STP/SOLAR_DATA/SOLAR_RADIO/FLUX/<br>
  1730.          *  <br>
  1731.          *  f107, f107A, and ap effects are neither large nor well established below 80 km
  1732.          *  and these parameters should be set to 150., 150., and 4. respectively.
  1733.          *  </p>
  1734.          *  @param alt altitude (km)
  1735.          */
  1736.         void gtd7d(final double alt) {

  1737.             // Compute densities and temperatures
  1738.             gtd7(alt);

  1739.             // Update the total mass density with anomalous oxygen contribution
  1740.             final double dTot = getDensity(TOTAL_MASS) + AMU * O_MASS * getDensity(ANOMALOUS_OXYGEN);
  1741.             setDensity(TOTAL_MASS, dTot);

  1742.         }

  1743.         /** Set one density.
  1744.          * @param index one of the nine elements :
  1745.          * <ul>
  1746.          * <li>{@link #HELIUM}</li>
  1747.          * <li>{@link #ATOMIC_OXYGEN}</li>
  1748.          * <li>{@link #MOLECULAR_NITROGEN}</li>
  1749.          * <li>{@link #MOLECULAR_OXYGEN}</li>
  1750.          * <li>{@link #ARGON}</li>
  1751.          * <li>{@link #TOTAL_MASS}</li>
  1752.          * <li>{@link #HYDROGEN}</li>
  1753.          * <li>{@link #ATOMIC_NITROGEN}</li>
  1754.          * <li>{@link #ATOMIC_NITROGEN}</li>
  1755.          * </ul>
  1756.          * @param d the value of density to set
  1757.          */
  1758.         void setDensity(final int index, final double d) {
  1759.             densities[index] = d;
  1760.         }

  1761.         /** Set one temperature.
  1762.          * @param index one of the two elements :
  1763.          * <ul>
  1764.          * <li>{@link #EXOSPHERIC}</li>
  1765.          * <li>{@link #ALTITUDE}</li>
  1766.          * </ul>
  1767.          * @param t the value of temperature to set
  1768.          */
  1769.         void setTemperature(final int index, final double t) {
  1770.             temperatures[index] = t;
  1771.         }

  1772.         /** Get one of the stored densities.
  1773.          * @param index one of the nine elements :
  1774.          * <ul>
  1775.          * <li>{@link #HELIUM}</li>
  1776.          * <li>{@link #ATOMIC_OXYGEN}</li>
  1777.          * <li>{@link #MOLECULAR_NITROGEN}</li>
  1778.          * <li>{@link #MOLECULAR_OXYGEN}</li>
  1779.          * <li>{@link #ARGON}</li>
  1780.          * <li>{@link #TOTAL_MASS}</li>
  1781.          * <li>{@link #HYDROGEN}</li>
  1782.          * <li>{@link #ATOMIC_NITROGEN}</li>
  1783.          * <li>{@link #ATOMIC_NITROGEN}</li>
  1784.          * </ul>
  1785.          * @return the requested density
  1786.          */
  1787.         public double getDensity(final int index) {
  1788.             return densities[index];
  1789.         }

  1790.         /** Calculate G(L) function with upper thermosphere parameters.
  1791.          *  @param p array of parameters
  1792.          *  @return G(L) value
  1793.          */
  1794.         private double globe7(final double[] p) {

  1795.             final double[] t = new double[14];
  1796.             final double cd32 = FastMath.cos(DAY_TO_RAD * (doy - p[31]));
  1797.             final double cd18 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[17]));
  1798.             final double cd14 = FastMath.cos(DAY_TO_RAD * (doy - p[13]));
  1799.             final double cd39 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[38]));

  1800.             // F10.7 effect
  1801.             final double df  = f107  - f107a;
  1802.             final double dfa = f107a - FLUX_REF;
  1803.             t[0] = p[19] * df * (1.0 + p[59] * dfa) + p[20] * df * df + p[21] * dfa + p[29] * dfa * dfa;

  1804.             final double f1 = 1.0 + (p[47] * dfa + p[19] * df + p[20] * df * df) * swc[1];
  1805.             final double f2 = 1.0 + (p[49] * dfa + p[19] * df + p[20] * df * df) * swc[1];

  1806.             // Time independent
  1807.             t[1] = (p[1]  * plg[0][2] + p[2] * plg[0][4] + p[22] * plg[0][6]) +
  1808.                    (p[14] * plg[0][2]) * dfa * swc[1] + p[26] * plg[0][1];

  1809.             // Symmetrical annual
  1810.             t[2] = p[18] * cd32;

  1811.             // Symmetrical semiannual
  1812.             t[3] = (p[15] + p[16] * plg[0][2]) * cd18;

  1813.             // Asymmetrical annual
  1814.             t[4] = f1 * (p[9] * plg[0][1] + p[10] * plg[0][3]) * cd14;

  1815.             // Asymmetrical semiannual
  1816.             t[5] = p[37] * plg[0][1] * cd39;

  1817.             // Diurnal
  1818.             if (sw[7] != 0) {
  1819.                 final double t71 = (p[11] * plg[1][2]) * cd14 * swc[5];
  1820.                 final double t72 = (p[12] * plg[1][2]) * cd14 * swc[5];
  1821.                 t[6] = f2 * ((p[3] * plg[1][1] + p[4] * plg[1][3] + p[27] * plg[1][5] + t71) * ctloc +
  1822.                              (p[6] * plg[1][1] + p[7] * plg[1][3] + p[28] * plg[1][5] + t72) * stloc);
  1823.             }

  1824.             // Semidiurnal
  1825.             if (sw[8] != 0) {
  1826.                 final double t81 = (p[23] * plg[2][3] + p[35] * plg[2][5]) * cd14 * swc[5];
  1827.                 final double t82 = (p[33] * plg[2][3] + p[36] * plg[2][5]) * cd14 * swc[5];
  1828.                 t[7] = f2 * ((p[5] * plg[2][2] + p[41] * plg[2][4] + t81) * c2tloc +
  1829.                              (p[8] * plg[2][2] + p[42] * plg[2][4] + t82) * s2tloc);
  1830.             }

  1831.             // Terdiurnal
  1832.             if (sw[14] != 0) {
  1833.                 t[13] = f2 * ((p[39] * plg[3][3] + (p[93] * plg[3][4] + p[46] * plg[3][6]) * cd14 * swc[5]) * s3tloc +
  1834.                               (p[40] * plg[3][3] + (p[94] * plg[3][4] + p[48] * plg[3][6]) * cd14 * swc[5]) * c3tloc);
  1835.             }

  1836.             // magnetic activity based on daily ap
  1837.             if (sw[9] == -1) {
  1838.                 if (p[51] != 0) {
  1839.                     final double exp1 = FastMath.exp(-10800.0 * FastMath.abs(p[51]) /
  1840.                                                      (1.0 + p[138] * (LAT_REF - FastMath.abs(lat))));
  1841.                     final double p24 = FastMath.max(p[24], 1.0e-4);
  1842.                     apt = sg0(FastMath.min(exp1, 0.99999), p24, p[25]);
  1843.                     t[8] = apt * (p[50] + p[96] * plg[0][2] + p[54] * plg[0][4] +
  1844.                                   (p[125] * plg[0][1] + p[126] * plg[0][3] + p[127] * plg[0][5]) * cd14 * swc[5] +
  1845.                                   (p[128] * plg[1][1] + p[129] * plg[1][3] + p[130] * plg[1][5]) * swc[7] *
  1846.                                   FastMath.cos(HOUR_TO_RAD * (hl - p[131])));
  1847.                 }
  1848.             } else {
  1849.                 final double apd = ap[0] - 4.0;
  1850.                 final double p44 = (p[43] < 0.) ? 1.0E-5 : p[43];
  1851.                 final double p45 = p[44];
  1852.                 apdf = apd + (p45 - 1.0) * (apd + (FastMath.exp(-p44 * apd) - 1.0) / p44);
  1853.                 if (sw[9] != 0) {
  1854.                     t[8] = apdf * (p[32] + p[45] * plg[0][2] + p[34] * plg[0][4] +
  1855.                                    (p[100] * plg[0][1] + p[101] * plg[0][3] + p[102] * plg[0][5]) * cd14 * swc[5] +
  1856.                                    (p[121] * plg[1][1] + p[122] * plg[1][3] + p[123] * plg[1][5]) * swc[7] *
  1857.                                    FastMath.cos(HOUR_TO_RAD * (hl - p[124])));
  1858.                 }
  1859.             }

  1860.             if (sw[10] != 0) {
  1861.                 final double lonr = DEG_TO_RAD * lon;
  1862.                 // Longitudinal
  1863.                 if (sw[11] != 0) {
  1864.                     t[10] = (1.0 + p[80] * dfa * swc[1]) *
  1865.                             ((p[64]  * plg[1][2] + p[65]  * plg[1][4] + p[66]  * plg[1][6] +
  1866.                               p[103] * plg[1][1] + p[104] * plg[1][3] + p[105] * plg[1][5] +
  1867.                              (p[109] * plg[1][1] + p[110] * plg[1][3] + p[111] * plg[1][5]) * swc[5] * cd14) *
  1868.                              FastMath.cos(lonr) +
  1869.                              (p[90]  * plg[1][2] + p[91]  * plg[1][4] + p[92]  * plg[1][6] +
  1870.                               p[106] * plg[1][1] + p[107] * plg[1][3] + p[108] * plg[1][5] +
  1871.                              (p[112] * plg[1][1] + p[113] * plg[1][3] + p[114] * plg[1][5]) * swc[5] * cd14) *
  1872.                              FastMath.sin(lonr));
  1873.                 }

  1874.                 // ut and mixed ut, longitude
  1875.                 if (sw[12] != 0) {
  1876.                     t[11] = (1.0 + p[95]  * plg[0][1]) * (1.0 + p[81] * dfa * swc[1]) *
  1877.                             (1.0 + p[119] * plg[0][1] * swc[5] * cd14) *
  1878.                             (p[68] * plg[0][1] + p[69] * plg[0][3] + p[70] * plg[0][5]) *
  1879.                             FastMath.cos(SEC_TO_RAD * (sec - p[71]));
  1880.                     t[11] += swc[11] * (1.0 + p[137] * dfa * swc[1]) *
  1881.                             (p[76] * plg[2][3] + p[77] * plg[2][5] + p[78] * plg[2][7]) *
  1882.                             FastMath.cos(SEC_TO_RAD * (sec - p[79]) + 2.0 * lonr);
  1883.                 }

  1884.                 /* ut, longitude magnetic activity */
  1885.                 if (sw[13] != 0) {
  1886.                     if (sw[9] == -1) {
  1887.                         if (p[51] != 0.) {
  1888.                             t[12] = apt * swc[11] * (1. + p[132] * plg[0][1]) *
  1889.                                     (p[52] * plg[1][2] + p[98] * plg[1][4] + p[67] * plg[1][6]) *
  1890.                                     FastMath.cos(DEG_TO_RAD * (lon - p[97])) +
  1891.                                     apt * swc[11] * swc[5] * cd14 *
  1892.                                     (p[133] * plg[1][1] + p[134] * plg[1][3] + p[135] * plg[1][5]) *
  1893.                                     FastMath.cos(DEG_TO_RAD * (lon - p[136])) +
  1894.                                     apt * swc[12] *
  1895.                                     (p[55] * plg[0][1] + p[56] * plg[0][3] + p[57] * plg[0][5]) *
  1896.                                     FastMath.cos(SEC_TO_RAD * (sec - p[58]));
  1897.                         }
  1898.                     } else {
  1899.                         t[12] = apdf * swc[11] * (1.0 + p[120] * plg[0][1]) *
  1900.                                 ((p[60] * plg[1][2] + p[61] * plg[1][4] + p[62] * plg[1][6]) *
  1901.                                 FastMath.cos(DEG_TO_RAD * (lon - p[63]))) +
  1902.                                 apdf * swc[11] * swc[5] * cd14 *
  1903.                                 (p[115] * plg[1][1] + p[116] * plg[1][3] + p[117] * plg[1][5]) *
  1904.                                 FastMath.cos(DEG_TO_RAD * (lon - p[118])) +
  1905.                                 apdf * swc[12] *
  1906.                                 (p[83] * plg[0][1] + p[84] * plg[0][3] + p[85] * plg[0][5]) *
  1907.                                 FastMath.cos(SEC_TO_RAD * (sec - p[75]));
  1908.                     }
  1909.                 }
  1910.             }

  1911.             // Sum all effects (params not used: 82, 89, 99, 139-149)
  1912.             double tinf = p[30];
  1913.             for (int i = 0; i < 14; i++) {
  1914.                 tinf += FastMath.abs(sw[i + 1]) * t[i];
  1915.             }

  1916.             // Return G(L)
  1917.             return tinf;

  1918.         }

  1919.         /** Calculate G(L) function with lower atmosphere parameters.
  1920.          *  @param p array of parameters
  1921.          *  @return G(L) value
  1922.          */
  1923.         private double glob7s(final double[] p) {

  1924.             final double[] t = new double[14];
  1925.             final double cd32 = FastMath.cos(DAY_TO_RAD * (doy - p[31]));
  1926.             final double cd18 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[17]));
  1927.             final double cd14 = FastMath.cos(DAY_TO_RAD * (doy - p[13]));
  1928.             final double cd39 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[38]));

  1929.             // F10.7 effect
  1930.             t[0] = p[21] * (f107a - FLUX_REF);

  1931.             // Time independent
  1932.             t[1] = p[1]  * plg[0][2] + p[2]  * plg[0][4] + p[22] * plg[0][6] +
  1933.                    p[26] * plg[0][1] + p[14] * plg[0][3] + p[59] * plg[0][5];

  1934.             // Symmetrical annual
  1935.             t[2] = (p[18] + p[47] * plg[0][2] + p[29] * plg[0][4]) * cd32;

  1936.             // Symmetrical semiannual
  1937.             t[3] = (p[15] + p[16] * plg[0][2] + p[30] * plg[0][4]) * cd18;

  1938.             // Asymmetrical annual
  1939.             t[4] = (p[9] * plg[0][1] + p[10] * plg[0][3] + p[20] * plg[0][5]) * cd14;

  1940.             // Asymmetrical semiannual
  1941.             t[5] = (p[37] * plg[0][1]) * cd39;

  1942.             // Diurnal
  1943.             if (sw[7] != 0) {
  1944.                 final double t71 = p[11] * plg[1][2] * cd14 * swc[5];
  1945.                 final double t72 = p[12] * plg[1][2] * cd14 * swc[5];
  1946.                 t[6] = (p[3] * plg[1][1] + p[4] * plg[1][3] + t71) * ctloc +
  1947.                        (p[6] * plg[1][1] + p[7] * plg[1][3] + t72) * stloc;
  1948.             }

  1949.             // Semidiurnal
  1950.             if (sw[8] != 0) {
  1951.                 final double t81 = (p[23] * plg[2][3] + p[35] * plg[2][5]) * cd14 * swc[5];
  1952.                 final double t82 = (p[33] * plg[2][3] + p[36] * plg[2][5]) * cd14 * swc[5];
  1953.                 t[7] = (p[5] * plg[2][2] + p[41] * plg[2][4] + t81) * c2tloc +
  1954.                        (p[8] * plg[2][2] + p[42] * plg[2][4] + t82) * s2tloc;
  1955.             }

  1956.             // Terdiurnal
  1957.             if (sw[14] != 0) {
  1958.                 t[13] = p[39] * plg[3][3] * s3tloc + p[40] * plg[3][3] * c3tloc;
  1959.             }

  1960.             // Magnetic activity
  1961.             if (sw[9] == 1) {
  1962.                 t[8] = apdf * (p[32] + p[45] * plg[0][2] * swc[2]);
  1963.             } else if (sw[9] == -1) {
  1964.                 t[8] = apt  * (p[50] + p[96] * plg[0][2] * swc[2]);
  1965.             }

  1966.             // Longitudinal
  1967.             if (!(sw[10] == 0 || sw[11] == 0)) {
  1968.                 final double lonr = DEG_TO_RAD * lon;
  1969.                 t[10] = (1.0 + plg[0][1] * (p[80] * swc[5] * FastMath.cos(DAY_TO_RAD * (doy - p[81])) +
  1970.                                             p[85] * swc[6] * FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[86]))) +
  1971.                                p[83] * swc[3] * FastMath.cos(DAY_TO_RAD * (doy - p[84])) +
  1972.                                p[87] * swc[4] * FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[88]))) *
  1973.                         ((p[64] * plg[1][2] + p[65] * plg[1][4] + p[66] * plg[1][6] +
  1974.                           p[74] * plg[1][1] + p[75] * plg[1][3] + p[76] * plg[1][5]) * FastMath.cos(lonr) +
  1975.                          (p[90] * plg[1][2] + p[91] * plg[1][4] + p[92] * plg[1][6] +
  1976.                           p[77] * plg[1][1] + p[78] * plg[1][3] + p[79] * plg[1][5]) * FastMath.sin(lonr));
  1977.             }

  1978.             // Sum all effects
  1979.             double gl = 0;
  1980.             for (int i = 0; i < 14; i++) {
  1981.                 gl += FastMath.abs(sw[i + 1]) * t[i];
  1982.             }

  1983.             // Return G(L)
  1984.             return gl;
  1985.         }

  1986.         /** Implements sg0 function (Eq. A24a).
  1987.          * @param ex ex
  1988.          * @param p24 abs(p[24])
  1989.          * @param p25 p[25]
  1990.          * @return sg0
  1991.          */
  1992.         private double sg0(final double ex, final double p24, final double p25) {
  1993.             final double g01 = g0(ap[1], p24, p25);
  1994.             final double g02 = g0(ap[2], p24, p25);
  1995.             final double g03 = g0(ap[3], p24, p25);
  1996.             final double g04 = g0(ap[4], p24, p25);
  1997.             final double g05 = g0(ap[5], p24, p25);
  1998.             final double g06 = g0(ap[6], p24, p25);
  1999.             final double ex2 = ex * ex;
  2000.             final double ex3 = ex * ex2;
  2001.             final double ex4 = ex2 * ex2;
  2002.             final double ex8 = ex4 * ex4;
  2003.             final double ex12 = ex4 * ex8;
  2004.             final double g234 = g02 * ex + g03 * ex2 + g04 * ex3;
  2005.             final double g56  = g05 * ex4 + g06 * ex12;
  2006.             final double ex19 = ex3 * ex4 * ex12;
  2007.             final double omex = 1.0 - ex;
  2008.             final double sumex = 1.0 + (1.0 - ex19) / omex * FastMath.sqrt(ex);
  2009.             return (g01 + (g234 + g56 * (1.0 - ex8) / omex)) / sumex;
  2010.         }

  2011.         /** Implements go function (Eq. A24d).
  2012.          * @param apI 3 hrs ap
  2013.          * @param p24 abs(p[24])
  2014.          * @param p25 p[25]
  2015.          * @return go
  2016.          */
  2017.         private double g0(final double apI, final double p24, final double p25) {
  2018.             final double am4 = apI - 4.0;
  2019.             return am4 + (p25 - 1.0) * (am4 + (FastMath.exp(-p24 * am4) - 1.0) / p24);
  2020.         }

  2021.         /** Calculates chemistry/dissociation correction for MSIS models.
  2022.          * @param alt altitude
  2023.          * @param r target ratio
  2024.          * @param h1 transition scale length
  2025.          * @param zh altitude of 1/2 R
  2026.          * @return correction
  2027.          */
  2028.         private double ccor(final double alt, final double r, final double h1, final double zh) {
  2029.             final double e = (alt - zh) / h1;
  2030.             if (e > 70.) {
  2031.                 return 1.;
  2032.             } else if (e < -70.) {
  2033.                 return FastMath.exp(r);
  2034.             } else {
  2035.                 return FastMath.exp(r / (1.0 + FastMath.exp(e)));
  2036.             }
  2037.         }


  2038.         /** Calculates O & O2 chemistry/dissociation correction for MSIS models.
  2039.          * @param alt altitude
  2040.          * @param r target ratio
  2041.          * @param h1 transition scale length
  2042.          * @param zh altitude of 1/2 R
  2043.          * @param h2 transition scale length
  2044.          * @return correction
  2045.          */
  2046.         private double ccor2(final double alt, final double r,
  2047.                              final double h1, final double zh, final double h2) {
  2048.             final double e1 = (alt - zh) / h1;
  2049.             final double e2 = (alt - zh) / h2;
  2050.             if ((e1 > 70.) || (e2 > 70.)) {
  2051.                 return 1.;
  2052.             } else if ((e1 < -70.) && (e2 < -70.)) {
  2053.                 return FastMath.exp(r);
  2054.             } else {
  2055.                 final double ex1 = FastMath.exp(e1);
  2056.                 final double ex2 = FastMath.exp(e2);
  2057.                 return FastMath.exp(r / (1.0 + 0.5 * (ex1 + ex2)));
  2058.             }
  2059.         }

  2060.         /** Calculates scale height.
  2061.          * @param alt altitude
  2062.          * @param xm species molecular weight
  2063.          * @param temp temperature
  2064.          * @return scale height (km)
  2065.          */
  2066.         private double scalh(final double alt, final double xm, final double temp) {
  2067.             // Gravity at altitude
  2068.             final double denom = 1.0 + alt / rlat;
  2069.             final double galt = glat / (denom * denom);
  2070.             return R_GAS * temp / (galt * xm);
  2071.         }

  2072.         /** Calculates turbopause correction for MSIS models.
  2073.          * @param dd diffusive density
  2074.          * @param dm full mixed density
  2075.          * @param zhm transition scale length
  2076.          * @param xmm full mixed molecular weight
  2077.          * @param xm species molecular weight
  2078.          * @return combined density
  2079.          */
  2080.         private double dnet(final double dd, final double dm,
  2081.                             final double zhm, final double xmm, final double xm) {
  2082.             if (!(dm > 0 && dd > 0)) {
  2083.                 double ddd = dd;
  2084.                 if (dd == 0 && dm == 0) {
  2085.                     ddd = 1;
  2086.                 }
  2087.                 if (dm == 0) {
  2088.                     return ddd;
  2089.                 }
  2090.                 if (dd == 0) {
  2091.                     return dm;
  2092.                 }
  2093.             }

  2094.             final double a  = zhm / (xmm - xm);
  2095.             final double ylog = a * FastMath.log(dm / dd);
  2096.             if (ylog < -10.) {
  2097.                 return dd;
  2098.             } else if (ylog > 10.) {
  2099.                 return dm;
  2100.             } else {
  2101.                 return dd * FastMath.pow(1.0 + FastMath.exp(ylog), 1.0 / a);
  2102.             }
  2103.         }

  2104.         /** Integrate cubic spline function from xa[0] to x.
  2105.          * <p>ADAPTED FROM NUMERICAL RECIPES</p>
  2106.          * @param xa array of abscissas in ascending order
  2107.          * @param ya array of ordinates in ascending order by xa
  2108.          * @param y2a array of second derivatives in ascending order by xa
  2109.          * @param x abscissa end point
  2110.          * @return integral value
  2111.          */
  2112.         private double splini(final double[] xa, final double[] ya, final double[] y2a, final double x) {
  2113.             final int n = xa.length;
  2114.             double yi = 0;
  2115.             int klo = 0;
  2116.             int khi = 1;
  2117.             while (x > xa[klo] && khi < n) {
  2118.                 double xx = x;
  2119.                 if (khi < n - 1) {
  2120.                     xx = (x < xa[khi]) ? x : xa[khi];
  2121.                 }
  2122.                 final double h = xa[khi] - xa[klo];
  2123.                 final double a = (xa[khi] - xx) / h;
  2124.                 final double b = (xx - xa[klo]) / h;
  2125.                 final double a2 = a * a;
  2126.                 final double b2 = b * b;
  2127.                 yi += ((1.0 - a2) * ya[klo] / 2.0 + b2 * ya[khi] / 2.0 +
  2128.                        ((-(1.0 + a2 * a2) / 4.0 + a2 / 2.0) * y2a[klo] +
  2129.                           (b2 * b2 / 4.0 - b2 / 2.0) * y2a[khi]) * h * h / 6.0) * h;
  2130.                 klo++;
  2131.                 khi++;
  2132.             }
  2133.             return yi;
  2134.         }

  2135.         /** Calculate cubic spline interpolated value.
  2136.          * <p>ADAPTED FROM NUMERICAL RECIPES</p>
  2137.          * @param xa array of abscissas in ascending order
  2138.          * @param ya array of ordinates in ascending order by xa
  2139.          * @param y2a array of second derivatives in ascending order by xa
  2140.          * @param x abscissa for interpolation
  2141.          * @return interpolated value
  2142.          */
  2143.         private double splint(final double[] xa, final double[] ya, final double[] y2a, final double x) {
  2144.             final int n = xa.length;
  2145.             int klo = 0;
  2146.             int khi = n - 1;
  2147.             while (khi - klo > 1) {
  2148.                 final int k = (khi + klo) >>> 1;
  2149.                 if (xa[k] > x) {
  2150.                     khi = k;
  2151.                 } else {
  2152.                     klo = k;
  2153.                 }
  2154.             }
  2155.             final double h = xa[khi] - xa[klo];
  2156.             final double a = (xa[khi] - x) / h;
  2157.             final double b = (x - xa[klo]) / h;
  2158.             return a * ya[klo] + b * ya[khi] +
  2159.                     ((a * a * a - a) * y2a[klo] + (b * b * b - b) * y2a[khi]) * h * h / 6.0;
  2160.         }

  2161.         /** Calculate 2nd derivatives of cubic spline interpolation function.
  2162.          * <p>ADAPTED FROM NUMERICAL RECIPES</p>
  2163.          * @param x array of abscissas in ascending order
  2164.          * @param y array of ordinates in ascending order by x
  2165.          * @param yp1 derivative at x[0] (2nd derivatives null if > 1E30)
  2166.          * @param ypn derivative at x[n-1] (2nd derivatives null if > 1E30)
  2167.          * @return array of second derivatives
  2168.          */
  2169.         private double[] spline(final double[] x, final double[] y, final double yp1, final double ypn) {
  2170.             final int n = x.length;
  2171.             final double[] y2 = new double[n];
  2172.             final double[] u  = new double[n];

  2173.             if (yp1 < 1e+30) {
  2174.                 y2[0] = -0.5;
  2175.                 u[0]  = (3.0 / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - yp1);
  2176.             }
  2177.             for (int i = 1; i < n - 1; i++) {
  2178.                 final double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
  2179.                 final double p = sig * y2[i - 1] + 2.0;
  2180.                 y2[i] = (sig - 1.0) / p;
  2181.                 u[i] = (6.0 * ((y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])) /
  2182.                         (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
  2183.             }

  2184.             double qn = 0;
  2185.             double un = 0;
  2186.             if (ypn < 1e+30) {
  2187.                 qn = 0.5;
  2188.                 un = (3.0 / (x[n - 1] - x[n - 2])) * (ypn - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]));
  2189.             }

  2190.             y2[n - 1] = (un - qn * u[n - 2]) / (qn * y2[n - 2] + 1.0);
  2191.             for (int k = n - 2; k >= 0; k--) {
  2192.                 y2[k] = y2[k] * y2[k + 1] + u[k];
  2193.             }

  2194.             return y2;
  2195.         }

  2196.         /** Calculate Temperature and Density Profiles for lower atmosphere.
  2197.          * @param alt altitude
  2198.          * @param d0 density
  2199.          * @param xm mixed density
  2200.          * @return temperature or density profile
  2201.          */
  2202.         private double densm(final double alt, final double d0, final double xm) {

  2203.             double densm = d0;

  2204.             // stratosphere/mesosphere temperature
  2205.             int mn = ZN2.length;
  2206.             double z = (alt > ZN2[mn - 1]) ? alt : ZN2[mn - 1];

  2207.             double z1 = ZN2[0];
  2208.             double z2 = ZN2[mn - 1];
  2209.             double t1 = meso_tn2[0];
  2210.             double t2 = meso_tn2[mn - 1];
  2211.             double zg  = zeta(z, z1);
  2212.             double zgdif = zeta(z2, z1);

  2213.             /* set up spline nodes */
  2214.             double[] xs = new double[mn];
  2215.             double[] ys = new double[mn];
  2216.             for (int k = 0; k < mn; k++) {
  2217.                 xs[k] = zeta(ZN2[k], z1) / zgdif;
  2218.                 ys[k] = 1.0 / meso_tn2[k];
  2219.             }
  2220.             final double qSM = (rlat + z2) / (rlat + z1);
  2221.             double yd1 = -meso_tgn2[0] / (t1 * t1) * zgdif;
  2222.             double yd2 = -meso_tgn2[1] / (t2 * t2) * zgdif * qSM * qSM;

  2223.             /* calculate spline coefficients */
  2224.             double[] y2out = spline(xs, ys, yd1, yd2);
  2225.             double x = zg / zgdif;
  2226.             double y = splint(xs, ys, y2out, x);

  2227.             /* temperature at altitude */
  2228.             double tz = 1.0 / y;

  2229.             if (xm != 0.0) {
  2230.                 /* calculate stratosphere / mesospehere density */
  2231.                 final double glb  = galt(z1);
  2232.                 final double gamm = xm * glb * zgdif / R_GAS;

  2233.                 /* Integrate temperature profile */
  2234.                 final double yi = splini(xs, ys, y2out, x);
  2235.                 final double expl = FastMath.min(50., gamm * yi);

  2236.                 /* Density at altitude */
  2237.                 densm *= (t1 / tz) * FastMath.exp(-expl);
  2238.             }

  2239.             if (alt > ZN3[0]) {
  2240.                 return (xm == 0.0) ? tz : densm;
  2241.             }

  2242.             // troposhere/stratosphere temperature
  2243.             z = alt;
  2244.             mn = ZN3.length;
  2245.             z1 = ZN3[0];
  2246.             z2 = ZN3[mn - 1];
  2247.             t1 = meso_tn3[0];
  2248.             t2 = meso_tn3[mn - 1];
  2249.             zg = zeta(z, z1);
  2250.             zgdif = zeta(z2, z1);

  2251.             /* set up spline nodes */
  2252.             xs = new double[mn];
  2253.             ys = new double[mn];
  2254.             for (int k = 0; k < mn; k++) {
  2255.                 xs[k] = zeta(ZN3[k], z1) / zgdif;
  2256.                 ys[k] = 1.0 / meso_tn3[k];
  2257.             }
  2258.             final double qTS = (rlat + z2) / (rlat + z1);
  2259.             yd1 = -meso_tgn3[0] / (t1 * t1) * zgdif;
  2260.             yd2 = -meso_tgn3[1] / (t2 * t2) * zgdif * qTS * qTS;

  2261.             /* calculate spline coefficients */
  2262.             y2out = spline(xs, ys, yd1, yd2);
  2263.             x = zg / zgdif;
  2264.             y = splint(xs, ys, y2out, x);

  2265.             /* temperature at altitude */
  2266.             tz = 1.0 / y;

  2267.             if (xm != 0.0) {
  2268.                 /* calculate tropospheric / stratosphere density */
  2269.                 final double glb = galt(z1);
  2270.                 final double gamm = xm * glb * zgdif / R_GAS;

  2271.                 /* Integrate temperature profile */
  2272.                 final double yi = splini(xs, ys, y2out, x);
  2273.                 final double expl = FastMath.min(50., gamm * yi);

  2274.                 /* Density at altitude */
  2275.                 densm *= (t1 / tz) * FastMath.exp(-expl);
  2276.             }

  2277.             return (xm == 0.0) ? tz : densm;
  2278.         }

  2279.         /** Calculate temperature and density profiles according to new lower thermo polynomial.
  2280.          * @param alt altitude
  2281.          * @param dlb density at lower boundary
  2282.          * @param tinf exospheric temperature
  2283.          * @param tlb temperature at lower boundary
  2284.          * @param xm species molecular weight
  2285.          * @param alpha thermal diffusion coefficient
  2286.          * @param zlb altitude of the lower boundary
  2287.          * @param s2 slope
  2288.          * @return temperature or density profile
  2289.          */
  2290.         private double densu(final double alt, final double dlb, final double tinf,
  2291.                              final double tlb, final double xm, final double alpha,
  2292.                              final double zlb, final double s2) {
  2293.             /* joining altitudes of Bates and spline */
  2294.             double z = (alt > ZN1[0]) ? alt : ZN1[0];

  2295.             /* geopotential altitude difference from ZLB */
  2296.             final double zg2 = zeta(z, zlb);

  2297.             /* Bates temperature */
  2298.             final double tt = tinf - (tinf - tlb) * FastMath.exp(-s2 * zg2);
  2299.             final double ta = tt;
  2300.             double tz = tt;

  2301.             final int mn = ZN1.length;
  2302.             final double[] xs = new double[mn];
  2303.             final double[] ys = new double[mn];
  2304.             double x = 0.;
  2305.             double[] y2out =  new double[mn];
  2306.             double zgdif = 0.;
  2307.             if (alt < ZN1[0]) {
  2308.                 /* calculate temperature below ZA
  2309.                  * temperature gradient at ZA from Bates profile */
  2310.                 final double p = (rlat + zlb) / (rlat + ZN1[0]);
  2311.                 final double dta = (tinf - ta) * s2 * p * p;
  2312.                 meso_tgn1[0] = dta;
  2313.                 meso_tn1[0] = ta;
  2314.                 z = (alt > ZN1[mn - 1]) ? alt : ZN1[mn - 1];

  2315.                 final double t1 = meso_tn1[0];
  2316.                 final double t2 = meso_tn1[mn - 1];
  2317.                 /* geopotental difference from z1 */
  2318.                 final double zg = zeta(z, ZN1[0]);
  2319.                 zgdif = zeta(ZN1[mn - 1], ZN1[0]);
  2320.                 /* set up spline nodes */
  2321.                 for (int k = 0; k < mn; k++) {
  2322.                     xs[k] = zeta(ZN1[k], ZN1[0]) / zgdif;
  2323.                     ys[k] = 1.0 / meso_tn1[k];
  2324.                 }
  2325.                 /* end node derivatives */
  2326.                 final double q   = (rlat + ZN1[mn - 1]) / (rlat + ZN1[0]);
  2327.                 final double yd1 = -meso_tgn1[0] / (t1 * t1) * zgdif;
  2328.                 final double yd2 = -meso_tgn1[1] / (t2 * t2) * zgdif * q * q;
  2329.                 /* calculate spline coefficients */
  2330.                 y2out = spline(xs, ys, yd1, yd2);
  2331.                 x = zg / zgdif;
  2332.                 final double y = splint(xs, ys, y2out, x);
  2333.                 /* temperature at altitude */
  2334.                 tz = 1.0 / y;
  2335.             }

  2336.             if (xm == 0) {
  2337.                 return tz;
  2338.             }

  2339.             /* calculate density above za */
  2340.             double glb   = galt(zlb);
  2341.             double gamma = xm * glb / (R_GAS * s2 * tinf);
  2342.             double expl  = (tt <= 0) ? 50. : FastMath.min(50., FastMath.exp(-s2 * gamma * zg2));
  2343.             double densu = dlb * FastMath.pow(tlb / tt, 1.0 + alpha + gamma) * expl;

  2344.             /* calculate density below za */
  2345.             if (alt < ZN1[0]) {
  2346.                 glb   = galt(ZN1[0]);
  2347.                 gamma = xm * glb * zgdif / R_GAS;
  2348.                 /* integrate spline temperatures */
  2349.                 expl  = (tz <= 0) ? 50.0 : FastMath.min(50., gamma * splini(xs, ys, y2out, x));
  2350.                 /* correct density at altitude */
  2351.                 densu *= FastMath.pow(meso_tn1[0] / tz, 1.0 + alpha) * FastMath.exp(-expl);
  2352.             }

  2353.             /* Return density at altitude */
  2354.             return densu;
  2355.         }

  2356.         /** Calculate gravity at altitude.
  2357.          * @param alt altitude (km)
  2358.          * @return gravity at altitude (cm/s2)
  2359.          */
  2360.         private double galt(final double alt) {
  2361.             final double r = 1.0 + alt / rlat;
  2362.             return glat / (r * r);
  2363.         }

  2364.         /** Calculate zeta function.
  2365.          * @param zz zz value
  2366.          * @param zl zl value
  2367.          * @return value of zeta function
  2368.          */
  2369.         private double zeta(final double zz, final double zl) {
  2370.             return (zz - zl) * (rlat + zl) / (rlat + zz);
  2371.         }

  2372.     }

  2373.     /**
  2374.      * This class is a placeholder for the computed densities and temperatures.
  2375.      * <p>
  2376.      * Densities are provided as an array d such as:
  2377.      * <ul>
  2378.      * <li>d[0] = He number density (1/m³)</li>
  2379.      * <li>d[1] = O number density (1/m³)</li>
  2380.      * <li>d[2] = N2 number density (1/m³)</li>
  2381.      * <li>d[3] = O2 number density (1/m³)</li>
  2382.      * <li>d[4] = Ar number density (1/m³)</li>
  2383.      * <li>d[5] = total mass density (kg/m³) (*)</li>
  2384.      * <li>d[6] = H number density (1/m³)</li>
  2385.      * <li>d[7] = N number density (1/m³)</li>
  2386.      * <li>d[8] = anomalous oxygen number density (1/m³)
  2387.      * </ul>
  2388.      * Total mass density, d[5], is NOT the same for methods gtd7 and gtd7d:
  2389.      * <ul>
  2390.      * <li>For gtd7: d[5] is the sum of the mass densities of the species
  2391.      * He, O, N2, O2, Ar, H and N but does NOT include anomalous oxygen.</li>
  2392.      * <li>For gtd7d: d[5] is the "effective total mass density for drag" and is the sum
  2393.      * of the mass densities of all species in this model, INCLUDING anomalous oxygen.</li>
  2394.      * </ul>
  2395.      * O, H, and N are set to zero below 72.5 km.
  2396.      * </p>
  2397.      * <p>
  2398.      * Temperatures are provided as an array t such as:
  2399.      * <ul>
  2400.      * <li>t[0] = exospheric temperature (K)</li>
  2401.      * <li>t[1] = temperature at altitude (K)</li>
  2402.      * </ul>
  2403.      * t[0] is set to global average for altitudes below 120 km.<br>
  2404.      * The 120 km gradient is left at global average value for altitudes below 72 km.
  2405.      * </p>
  2406.      * @param <T> type of the field elements
  2407.      * @since 9.0
  2408.      */
  2409.     public class FieldOutput<T extends RealFieldElement<T>> {

  2410.         /** Type of the field elements. */
  2411.         private final Field<T> field;

  2412.         /** Zero for the field. */
  2413.         private final T zero;

  2414.         /** Day of year (from 1 to 365 or 366). */
  2415.         private final int doy;

  2416.         /** Seconds in day (UT scale). */
  2417.         private final T sec;

  2418.         /** Geodetic latitude (°). */
  2419.         private final T lat;

  2420.         /** Geodetic longitude (°). */
  2421.         private final T lon;

  2422.         /** Local apparent solar time (hours). */
  2423.         private final T hl;

  2424.         /** 81 day average of F10.7 flux (centered on day). */
  2425.         private final double f107a;

  2426.         /** Daily F10.7 flux for previous day. */
  2427.         private final double f107;

  2428.         /** Array containing:
  2429.         *  <ul>
  2430.         *  <li>0: daily Ap</li>
  2431.         *  <li>1: 3 hr ap index for current time</li>
  2432.         *  <li>2: 3 hr ap index for 3 hrs before current time</li>
  2433.         *  <li>3: 3 hr ap index for 6 hrs before current time</li>
  2434.         *  <li>4: 3 hr ap index for FOR 9 hrs before current time</li>
  2435.         *  <li>5: average of eight 3 hr ap indices from 12 to 33 hrs prior to current time</li>
  2436.         *  <li>6: average of eight 3 hr ap indices from 36 to 57 hrs prior to current time</li>
  2437.         *  </ul>. */
  2438.         private final double[] ap;

  2439.         /** Gravity at latitude (cm/s2). */
  2440.         private final T glat;

  2441.         /** Effective Earth radius at latitude (km). */
  2442.         private final T rlat;

  2443.         /** N2 mixed density at alt. */
  2444.         private T dm28;

  2445.         /** Legendre polynomials. */
  2446.         private final T[][] plg;

  2447.         /** Cosinus of local solar time. */
  2448.         private final T ctloc;
  2449.         /** Sinus of local solar time. */
  2450.         private final T stloc;
  2451.         /** Square of ctloc. */
  2452.         private final T c2tloc;
  2453.         /** Square of stloc. */
  2454.         private final T s2tloc;
  2455.         /** Cube of ctloc. */
  2456.         private final T c3tloc;
  2457.         /** Cube of stloc. */
  2458.         private final T s3tloc;

  2459.         /** Magnetic activity based on daily ap. */
  2460.         private double apdf;

  2461.         /** Magnetic activity based on daily ap. */
  2462.         private T apt;

  2463.         /** Temperature at nodes for ZN1 scale. */
  2464.         private final T[] meso_tn1;

  2465.         /** Temperature at nodes for ZN2 scale. */
  2466.         private final T[] meso_tn2;

  2467.         /** Temperature at nodes for ZN3 scale. */
  2468.         private final T[] meso_tn3;

  2469.         /** Temperature gradients at end nodes for ZN1 scale. */
  2470.         private final T[] meso_tgn1;

  2471.         /** Temperature gradients at end nodes for ZN2 scale. */
  2472.         private final T[] meso_tgn2;

  2473.         /** Temperature gradients at end nodes for ZN3 scale. */
  2474.         private final T[] meso_tgn3;

  2475.         /** Densities. */
  2476.         private final T[] densities;

  2477.         /** Temperatures. */
  2478.         private final T[] temperatures;

  2479.         /** Simple constructor.
  2480.          *  @param doy day of year (from 1 to 365 or 366)
  2481.          *  @param sec seconds in day (UT scale)
  2482.          *  @param lat geodetic latitude (°)
  2483.          *  @param lon geodetic longitude (°)
  2484.          *  @param hl local apparent solar time (hours)
  2485.          *  @param f107a 81 day average of F10.7 flux (centered on day)
  2486.          *  @param f107 daily F10.7 flux for previous day
  2487.          *  @param ap array containing:
  2488.          *  <ul>
  2489.          *  <li>0: daily Ap</li>
  2490.          *  <li>1: 3 hr ap index for current time</li>
  2491.          *  <li>2: 3 hr ap index for 3 hrs before current time</li>
  2492.          *  <li>3: 3 hr ap index for 6 hrs before current time</li>
  2493.          *  <li>4: 3 hr ap index for FOR 9 hrs before current time</li>
  2494.          *  <li>5: average of eight 3 hr ap indices from 12 to 33 hrs prior to current time</li>
  2495.          *  <li>6: average of eight 3 hr ap indices from 36 to 57 hrs prior to current time</li>
  2496.          *  </ul>
  2497.          */
  2498.         FieldOutput(final int doy, final T sec,
  2499.                     final T lat, final T lon, final T hl,
  2500.                     final double f107a, final double f107, final double[] ap) {

  2501.             this.field = sec.getField();
  2502.             this.zero = field.getZero();

  2503.             this.doy   = doy;
  2504.             this.sec   = sec;
  2505.             this.lat   = lat;
  2506.             this.lon   = lon;
  2507.             this.hl    = hl;
  2508.             this.f107a = f107a;
  2509.             this.f107  = f107;
  2510.             this.ap    = ap.clone();

  2511.             this.plg       = MathArrays.buildArray(field, 4, 8);

  2512.             this.meso_tn1  = MathArrays.buildArray(field, ZN1.length);
  2513.             this.meso_tn2  = MathArrays.buildArray(field, ZN2.length);
  2514.             this.meso_tn3  = MathArrays.buildArray(field, ZN3.length);
  2515.             this.meso_tgn1 = MathArrays.buildArray(field, 2);
  2516.             this.meso_tgn2 = MathArrays.buildArray(field, 2);
  2517.             this.meso_tgn3 = MathArrays.buildArray(field, 2);

  2518.             densities       = MathArrays.buildArray(field, 9);
  2519.             temperatures    = MathArrays.buildArray(field, 2);

  2520.             // Calculates latitude variable gravity and effective radius
  2521.             final T xlat = (sw[2] == 0) ? zero.add(LAT_REF) : lat;
  2522.             final T c2   = xlat.multiply(2 * DEG_TO_RAD).cos();
  2523.             glat = c2.multiply(-0.0026373).add(1).multiply(G_REF);
  2524.             rlat = glat.multiply(2).divide(c2.multiply(2.27e-9).add(3.085462e-6)).multiply(1.e-5);

  2525.             // Convert latitude into radians
  2526.             final T latr = lat.multiply(DEG_TO_RAD);

  2527.             // Calculate legendre polynomials
  2528.             final T c = latr.sin();
  2529.             final T s = latr.cos();

  2530.             plg[0][1] = c;
  2531.             plg[0][2] = c.multiply( 3.0).multiply(plg[0][1]).subtract(1.0).divide(2.0);
  2532.             plg[0][3] = c.multiply( 5.0).multiply(plg[0][2]).subtract(plg[0][1].multiply(2.0)).divide(3.0);
  2533.             plg[0][4] = c.multiply( 7.0).multiply(plg[0][3]).subtract(plg[0][2].multiply(3.0)).divide(4.0);
  2534.             plg[0][5] = c.multiply( 9.0).multiply(plg[0][4]).subtract(plg[0][3].multiply(4.0)).divide(5.0);
  2535.             plg[0][6] = c.multiply(11.0).multiply(plg[0][5]).subtract(plg[0][4].multiply(5.0)).divide(6.0);

  2536.             plg[1][1] = s;
  2537.             plg[1][2] = c.multiply( 3.0).multiply(plg[1][1]);
  2538.             plg[1][3] = c.multiply( 5.0).multiply(plg[1][2]).subtract(plg[1][1].multiply(3.0)).divide(2.0);
  2539.             plg[1][4] = c.multiply( 7.0).multiply(plg[1][3]).subtract(plg[1][2].multiply(4.0)).divide(3.0);
  2540.             plg[1][5] = c.multiply( 9.0).multiply(plg[1][4]).subtract(plg[1][3].multiply(5.0)).divide(4.0);
  2541.             plg[1][6] = c.multiply(11.0).multiply(plg[1][5]).subtract(plg[1][4].multiply(6.0)).divide(5.0);

  2542.             plg[2][2] = s.multiply( 3.0).multiply(plg[1][1]);
  2543.             plg[2][3] = c.multiply( 5.0).multiply(plg[2][2]);
  2544.             plg[2][4] = c.multiply( 7.0).multiply(plg[2][3]).subtract(plg[2][2].multiply(5.0)).divide(2.0);
  2545.             plg[2][5] = c.multiply( 9.0).multiply(plg[2][4]).subtract(plg[2][3].multiply(6.0)).divide(3.0);
  2546.             plg[2][6] = c.multiply(11.0).multiply(plg[2][5]).subtract(plg[2][4].multiply(7.0)).divide(4.0);
  2547.             plg[2][7] = c.multiply(13.0).multiply(plg[2][6]).subtract(plg[2][5].multiply(8.0)).divide(5.0);

  2548.             plg[3][3] = s.multiply( 5.0).multiply(plg[2][2]);
  2549.             plg[3][4] = c.multiply( 7.0).multiply(plg[3][3]);
  2550.             plg[3][5] = c.multiply( 9.0).multiply(plg[3][4]).subtract(plg[3][3].multiply(7.0)).divide(2.0);
  2551.             plg[3][6] = c.multiply(11.0).multiply(plg[3][5]).subtract(plg[3][4].multiply(8.0)).divide(3.0);

  2552.             // Calculate additional data
  2553.             if (!(sw[7] == 0 && sw[8] == 0 && sw[14] == 0)) {
  2554.                 final T tloc = hl.multiply(HOUR_TO_RAD);
  2555.                 final T tlx2 = tloc.add(tloc);
  2556.                 final T tlx3 = tloc.add(tlx2);
  2557.                 stloc  = tloc.sin();
  2558.                 ctloc  = tloc.cos();
  2559.                 s2tloc = tlx2.sin();
  2560.                 c2tloc = tlx2.cos();
  2561.                 s3tloc = tlx3.sin();
  2562.                 c3tloc = tlx3.cos();
  2563.             } else {
  2564.                 stloc  = zero;
  2565.                 ctloc  = zero;
  2566.                 s2tloc = zero;
  2567.                 c2tloc = zero;
  2568.                 s3tloc = zero;
  2569.                 c3tloc = zero;
  2570.             }

  2571.         }

  2572.         /** Calculate temperatures and densities not including anomalous oxygen.
  2573.          *  <p>
  2574.          *  This method is the thermospheric portion of NRLMSISE-00 for alt > 72.5 km.
  2575.          *  </p>
  2576.          *  <p>NOTES ON INPUT VARIABLES:<br>
  2577.          *  Seconds, Local Time, and Longitude are used independently in the
  2578.          *  model and are not of equal importance for every situation.<br>
  2579.          *  For the most physically realistic calculation these three
  2580.          *  variables should be consistent (lst=sec/3600 + lon/15).<br>
  2581.          *  The Equation of Time departures from the above formula
  2582.          *  for apparent local time can be included if available but
  2583.          *  are of minor importance.<br><br>
  2584.          *
  2585.          *  f107 and f107A values used to generate the model correspond
  2586.          *  to the 10.7 cm radio flux at the actual distance of the Earth
  2587.          *  from the Sun rather than the radio flux at 1 AU. The following
  2588.          *  site provides both classes of values:<br>
  2589.          *  ftp://ftp.ngdc.noaa.gov/STP/SOLAR_DATA/SOLAR_RADIO/FLUX/<br><br>
  2590.          *
  2591.          *  f107, f107A, and ap effects are neither large nor well established below 80 km
  2592.          *  and these parameters should be set to 150., 150., and 4. respectively.
  2593.          *  </p>
  2594.          *  @param alt altitude (km)
  2595.          */
  2596.         void gts7(final T alt) {

  2597.             // Thermal diffusion coefficients for species
  2598.             final double[] alpha = {-0.38, 0.0, 0.0, 0.0, 0.17, 0.0, -0.38, 0.0, 0.0};
  2599.             // Altitude limits for net density computation for species
  2600.             final double[] altl  = {200.0, 300.0, 160.0, 250.0, 240.0, 450.0, 320.0, 450.0};
  2601.             // N2 mixed density
  2602.             final double xmm = PDM[2][4];

  2603.             /**** Exospheric temperature ****/
  2604.             T tinf = zero.add(PTM[0] * PT[0]);
  2605.             // Tinf variations not important below ZA or ZN[0]
  2606.             if (alt.getReal() > ZN1[0]) {
  2607.                 tinf = tinf.multiply(globe7(PT).multiply(sw[16]).add(1));
  2608.             }
  2609.             setTemperature(EXOSPHERIC, tinf);

  2610.             // Gradient variations not important below ZN[4]
  2611.             T g0 = zero.add(PTM[3] * PS[0]);
  2612.             if (alt.getReal() > ZN1[4]) {
  2613.                 g0 = g0.multiply(globe7(PS).multiply(sw[19]).add(1));
  2614.             }

  2615.             // Temperature at lower boundary
  2616.             T tlb = zero.add(PTM[1] * PD[3][0]);
  2617.             tlb = tlb.multiply(globe7(PD[3]).multiply(sw[17]).add(1));

  2618.             // Slope
  2619.             final T s = g0.divide(tinf.subtract(tlb));

  2620.             // Lower thermosphere temp variations not significant for density above 300 km
  2621.             meso_tn1[1]  = zero.add(PTM[6] * PTL[0][0]);
  2622.             meso_tn1[2]  = zero.add(PTM[2] * PTL[1][0]);
  2623.             meso_tn1[3]  = zero.add(PTM[7] * PTL[2][0]);
  2624.             meso_tn1[4]  = zero.add(PTM[4] * PTL[3][0]);
  2625.             meso_tgn1[1] = zero.add(PTM[8] * PMA[8][0]);
  2626.             if (alt.getReal() < 300.0) {
  2627.                 final double r = PTM[4] * PTL[3][0];
  2628.                 meso_tn1[1]  =  meso_tn1[1].divide(glob7s(PTL[0]).multiply(sw[18]         ).negate().add(1));
  2629.                 meso_tn1[2]  =  meso_tn1[2].divide(glob7s(PTL[1]).multiply(sw[18]         ).negate().add(1));
  2630.                 meso_tn1[3]  =  meso_tn1[3].divide(glob7s(PTL[2]).multiply(sw[18]         ).negate().add(1));
  2631.                 meso_tn1[4]  =  meso_tn1[4].divide(glob7s(PTL[3]).multiply(sw[18] * sw[20]).negate().add(1));
  2632.                 meso_tgn1[1] =  meso_tgn1[1].multiply(glob7s(PMA[8]).multiply(sw[18] * sw[20]).add(1));
  2633.                 meso_tgn1[1] =  meso_tgn1[1].multiply(meso_tn1[4].multiply(meso_tn1[4]).divide(r * r));
  2634.             }

  2635.             /**** Temperature at altitude ****/
  2636.             setTemperature(ALTITUDE, densu(alt, zero.add(1.0), tinf, tlb, 0, 0, PTM[5], s));

  2637.             /**** N2 density ****/
  2638.             /*   Density variation factor at Zlb */
  2639.             final T g28 = globe7(PD[2]).multiply(sw[21]);
  2640.             /* Diffusive density at Zlb */
  2641.             final T db28 = g28.exp().multiply(PDM[2][0] * PD[2][0]);
  2642.             /* Diffusive density at Alt */
  2643.             T diffusiveDensity = densu(alt, db28, tinf, tlb, N2_MASS, alpha[2], PTM[5], s);
  2644.             setDensity(MOLECULAR_NITROGEN, diffusiveDensity);
  2645.             // Variation of turbopause height
  2646.             final T zhf = lat.multiply(DEG_TO_RAD).sin().
  2647.                             multiply(sw[5] * PDL[0][24] * FastMath.cos(DAY_TO_RAD * (doy - PT[13]))).
  2648.                             add(1).
  2649.                             multiply(PDL[1][24]);
  2650.             /* Turbopause */
  2651.             final T zh28  = zhf.multiply(PDM[2][2]);
  2652.             final double zhm28 = PDM[2][3] * PDL[1][5];
  2653.             /* Mixed density at Zlb */
  2654.             final T b28 = densu(zh28, db28, tinf, tlb, N2_MASS - xmm, alpha[2] - 1.0, PTM[5], s);
  2655.             if (sw[15] != 0 && alt.getReal() <= altl[2]) {
  2656.                 /*  Mixed density at Alt */
  2657.                 dm28 = densu(alt, b28, tinf, tlb, xmm, alpha[2], PTM[5], s);
  2658.                 /*  Net density at Alt */
  2659.                 setDensity(MOLECULAR_NITROGEN, dnet(diffusiveDensity, dm28, zhm28, xmm, N2_MASS));
  2660.             } else {
  2661.                 dm28 = zero;
  2662.             }

  2663.             /**** He density ****/
  2664.             /*   Density variation factor at Zlb */
  2665.             final T g4 = globe7(PD[0]).multiply(sw[21]);
  2666.             /*  Diffusive density at Zlb */
  2667.             final T db04 = g4.exp().multiply(PDM[0][0] * PD[0][0]);
  2668.             /*  Diffusive density at Alt */
  2669.             diffusiveDensity = densu(alt, db04, tinf, tlb, HE_MASS, alpha[0], PTM[5], s);
  2670.             setDensity(HELIUM, diffusiveDensity);
  2671.             if (sw[15] != 0 && alt.getReal() < altl[0]) {
  2672.                 /*  Turbopause */
  2673.                 final double zh04 = PDM[0][2];
  2674.                 /*  Mixed density at Zlb */
  2675.                 final T b04 = densu(zero.add(zh04), db04, tinf, tlb, HE_MASS - xmm, alpha[0] - 1., PTM[5], s);
  2676.                 /*  Mixed density at Alt */
  2677.                 final T dm04 = densu(alt, b04, tinf, tlb, xmm, 0., PTM[5], s);
  2678.                 final double zhm04 = zhm28;
  2679.                 /*  Net density at Alt */
  2680.                 diffusiveDensity = dnet(diffusiveDensity, dm04, zhm04, xmm, HE_MASS);
  2681.                 /*  Correction to specified mixing ratio at ground */
  2682.                 final T rl = b28.multiply(PDM[0][1]).divide(b04).log();
  2683.                 final double zc04 = PDM[0][4] * PDL[1][0];
  2684.                 final double hc04 = PDM[0][5] * PDL[1][1];
  2685.                 /*  Net density corrected at Alt */
  2686.                 setDensity(HELIUM, diffusiveDensity.multiply(ccor(alt, rl, hc04, zc04)));
  2687.             }

  2688.             /**** O density ****/
  2689.             /* Density variation factor at Zlb */
  2690.             final T g16 = globe7(PD[1]).multiply(sw[21]);
  2691.             /* Diffusive density at Zlb */
  2692.             final T db16 = g16.exp().multiply(PDM[1][0] * PD[1][0]);
  2693.             /* Diffusive density at Alt */
  2694.             diffusiveDensity = densu(alt, db16, tinf, tlb, O_MASS, alpha[1], PTM[5], s);
  2695.             setDensity(ATOMIC_OXYGEN, diffusiveDensity);
  2696.             if (sw[15] != 0 && alt.getReal() < altl[1]) {
  2697.                 /* Turbopause */
  2698.                 final double zh16 = PDM[1][2];
  2699.                 /* Mixed density at Zlb */
  2700.                 final T b16 = densu(zero.add(zh16), db16, tinf, tlb, O_MASS - xmm, alpha[1] - 1.0, PTM[5], s);
  2701.                 /* Mixed density at Alt */
  2702.                 final T dm16 = densu(alt, b16, tinf, tlb, xmm, 0., PTM[5], s);
  2703.                 final double zhm16 = zhm28;
  2704.                 /* Net density at Alt */
  2705.                 diffusiveDensity = dnet(diffusiveDensity, dm16, zhm16, xmm, O_MASS);
  2706.                 final double rl = PDM[1][1] * PDL[1][16] * (1.0 + sw[1] * PDL[0][23] * (f107a - FLUX_REF));
  2707.                 final double hc16 = PDM[1][5] * PDL[1][3];
  2708.                 final double zc16 = PDM[1][4] * PDL[1][2];
  2709.                 final double hc216 = PDM[1][5] * PDL[1][4];
  2710.                 diffusiveDensity = diffusiveDensity.multiply(ccor2(alt, rl, hc16, zc16, hc216));
  2711.                 /* Chemistry correction */
  2712.                 final double hcc16 = PDM[1][7] * PDL[1][13];
  2713.                 final double zcc16 = PDM[1][6] * PDL[1][12];
  2714.                 final double rc16  = PDM[1][3] * PDL[1][14];
  2715.                 /* Net density corrected at Alt */
  2716.                 setDensity(ATOMIC_OXYGEN, diffusiveDensity.multiply(ccor(alt, zero.add(rc16), hcc16, zcc16)));
  2717.             }

  2718.             /**** O2 density ****/
  2719.             /* Density variation factor at Zlb */
  2720.             final T g32 = globe7(PD[4]).multiply(sw[21]);
  2721.             /* Diffusive density at Zlb */
  2722.             final T db32 = g32.exp().multiply(PDM[3][0] * PD[4][0]);
  2723.             /* Diffusive density at Alt */
  2724.             diffusiveDensity = densu(alt, db32, tinf, tlb, O2_MASS, alpha[3], PTM[5], s);
  2725.             setDensity(MOLECULAR_OXYGEN, diffusiveDensity);
  2726.             if (sw[15] != 0) {
  2727.                 if (alt.getReal() <= altl[3]) {
  2728.                     /* Turbopause */
  2729.                     final double zh32 = PDM[3][2];
  2730.                     /* Mixed density at Zlb */
  2731.                     final T b32 = densu(zero.add(zh32), db32, tinf, tlb, O2_MASS - xmm, alpha[3] - 1., PTM[5], s);
  2732.                     /* Mixed density at Alt */
  2733.                     final T dm32 = densu(alt, b32, tinf, tlb, xmm, 0., PTM[5], s);
  2734.                     final double zhm32 = zhm28;
  2735.                     /* Net density at Alt */
  2736.                     diffusiveDensity = dnet(diffusiveDensity, dm32, zhm32, xmm, O2_MASS);
  2737.                     /* Correction to specified mixing ratio at ground */
  2738.                     final T rl = b28.multiply(PDM[3][1]).divide(b32).log();
  2739.                     final double hc32 = PDM[3][5] * PDL[1][7];
  2740.                     final double zc32 = PDM[3][4] * PDL[1][6];
  2741.                     diffusiveDensity = diffusiveDensity.multiply(ccor(alt, rl, hc32, zc32));
  2742.                 }
  2743.                 /* Correction for general departure from diffusive equilibrium above Zlb */
  2744.                 final double hcc32  = PDM[3][7] * PDL[1][22];
  2745.                 final double hcc232 = PDM[3][7] * PDL[0][22];
  2746.                 final double zcc32  = PDM[3][6] * PDL[1][21];
  2747.                 final double rc32   = PDM[3][3] * PDL[1][23] * (1. + sw[1] * PDL[0][23] * (f107a - FLUX_REF));
  2748.                 /* Net density corrected at Alt */
  2749.                 setDensity(MOLECULAR_OXYGEN, diffusiveDensity.multiply(ccor2(alt, rc32, hcc32, zcc32, hcc232)));
  2750.             }

  2751.             /**** Ar density ****/
  2752.             /* Density variation factor at Zlb */
  2753.             final T g40 = globe7(PD[5]).multiply(sw[21]);
  2754.             /* Diffusive density at Zlb */
  2755.             final T db40 = g40.exp().multiply(PDM[4][0] * PD[5][0]);
  2756.             /* Diffusive density at Alt */
  2757.             diffusiveDensity = densu(alt, db40, tinf, tlb, AR_MASS, alpha[4], PTM[5], s);
  2758.             setDensity(ARGON, diffusiveDensity);
  2759.             if (sw[15] != 0 && alt.getReal() <= altl[4]) {
  2760.                 /* Turbopause */
  2761.                 final double zh40 = PDM[4][2];
  2762.                 /* Mixed density at Zlb */
  2763.                 final T b40 = densu(zero.add(zh40), db40, tinf, tlb, AR_MASS - xmm, alpha[4] - 1., PTM[5], s);
  2764.                 /* Mixed density at Alt */
  2765.                 final T dm40 = densu(alt, b40, tinf, tlb, xmm, 0., PTM[5], s);
  2766.                 final double zhm40 = zhm28;
  2767.                 /* Net density at Alt */
  2768.                 diffusiveDensity = dnet(diffusiveDensity, dm40, zhm40, xmm, AR_MASS);
  2769.                 /* Correction to specified mixing ratio at ground */
  2770.                 final T rl = b28.multiply(PDM[4][1]).divide(b40).log();
  2771.                 final double hc40 = PDM[4][5] * PDL[1][9];
  2772.                 final double zc40 = PDM[4][4] * PDL[1][8];
  2773.                 /* Net density corrected at Alt */
  2774.                 setDensity(ARGON, diffusiveDensity.multiply(ccor(alt, rl, hc40, zc40)));
  2775.             }

  2776.             /**** H density ****/
  2777.             /* Density variation factor at Zlb */
  2778.             final T g1 = globe7(PD[6]).multiply(sw[21]);
  2779.             /* Diffusive density at Zlb */
  2780.             final T db01 = g1.exp().multiply(PDM[5][0] * PD[6][0]);
  2781.             /* Diffusive density at Alt */
  2782.             diffusiveDensity = densu(alt, db01, tinf, tlb, H_MASS, alpha[6], PTM[5], s);
  2783.             setDensity(HYDROGEN, diffusiveDensity);
  2784.             if (sw[15] != 0 && alt.getReal() <= altl[6]) {
  2785.                 /* Turbopause */
  2786.                 final double zh01 = PDM[5][2];
  2787.                 /* Mixed density at Zlb */
  2788.                 final T b01 = densu(zero.add(zh01), db01, tinf, tlb, H_MASS - xmm, alpha[6] - 1., PTM[5], s);
  2789.                 /* Mixed density at Alt */
  2790.                 final T dm01 = densu(alt, b01, tinf, tlb, xmm, 0., PTM[5], s);
  2791.                 final double zhm01 = zhm28;
  2792.                 /* Net density at Alt */
  2793.                 diffusiveDensity = dnet(diffusiveDensity, dm01, zhm01, xmm, H_MASS);
  2794.                 /* Correction to specified mixing ratio at ground */
  2795.                 final T rl = b28.multiply(PDM[5][1] * FastMath.sqrt(PDL[1][17] * PDL[1][17])).divide(b01).log();
  2796.                 final double hc01 = PDM[5][5] * PDL[1][11];
  2797.                 final double zc01 = PDM[5][4] * PDL[1][10];
  2798.                 diffusiveDensity = diffusiveDensity.multiply(ccor(alt, rl, hc01, zc01));
  2799.                 /* Chemistry correction */
  2800.                 final double hcc01 = PDM[5][7] * PDL[1][19];
  2801.                 final double zcc01 = PDM[5][6] * PDL[1][18];
  2802.                 final double rc01 = PDM[5][3] * PDL[1][20];
  2803.                 /* Net density corrected at Alt */
  2804.                 setDensity(HYDROGEN, diffusiveDensity.multiply(ccor(alt, zero.add(rc01), hcc01, zcc01)));
  2805.             }

  2806.             /**** N density ****/
  2807.             /* Density variation factor at Zlb */
  2808.             final T g14 = globe7(PD[7]).multiply(sw[21]);
  2809.             /* Diffusive density at Zlb */
  2810.             final T db14 = g14.exp().multiply(PDM[6][0] * PD[7][0]);
  2811.             /* Diffusive density at Alt */
  2812.             diffusiveDensity = densu(alt, db14, tinf, tlb, N_MASS, alpha[7], PTM[5], s);
  2813.             setDensity(ATOMIC_NITROGEN, diffusiveDensity);
  2814.             if (sw[15] != 0 && alt.getReal() <= altl[7]) {
  2815.                 /* Turbopause */
  2816.                 final double zh14 = PDM[6][2];
  2817.                 /* Mixed density at Zlb */
  2818.                 final T b14 = densu(zero.add(zh14), db14, tinf, tlb, N_MASS - xmm, alpha[7] - 1., PTM[5], s);
  2819.                 /* Mixed density at Alt */
  2820.                 final T dm14 = densu(alt, b14, tinf, tlb, xmm, 0., PTM[5], s);
  2821.                 final double zhm14 = zhm28;
  2822.                 /* Net density at Alt */
  2823.                 diffusiveDensity = dnet(diffusiveDensity, dm14, zhm14, xmm, N_MASS);
  2824.                 /* Correction to specified mixing ratio at ground */
  2825.                 final T rl = b28.multiply(PDM[6][1] * PDL[0][2]).divide(b14).log();
  2826.                 final double hc14 = PDM[6][5] * PDL[0][1];
  2827.                 final double zc14 = PDM[6][4] * PDL[0][0];
  2828.                 diffusiveDensity = diffusiveDensity.multiply(ccor(alt, rl, hc14, zc14));
  2829.                 /* Chemistry correction */
  2830.                 final double hcc14 = PDM[6][7] * PDL[0][4];
  2831.                 final double zcc14 = PDM[6][6] * PDL[0][3];
  2832.                 final double rc14 = PDM[6][3] * PDL[0][5];
  2833.                 /* Net density corrected at Alt */
  2834.                 setDensity(ATOMIC_NITROGEN, diffusiveDensity.multiply(ccor(alt, zero.add(rc14), hcc14, zcc14)));
  2835.             }

  2836.             /**** Anomalous O density ****/
  2837.             final T g16h = globe7(PD[8]).multiply(sw[21]);
  2838.             final T db16h = g16h.exp().multiply(PDM[7][0] * PD[8][0]);
  2839.             final double tho   = PDM[7][9] * PDL[0][6];
  2840.             diffusiveDensity = densu(alt, db16h, zero.add(tho), zero.add(tho), O_MASS, alpha[8], PTM[5], s);
  2841.             final double zsht = PDM[7][5];
  2842.             final double zmho = PDM[7][4];
  2843.             final T zsho = scalh(zmho, O_MASS, tho);
  2844.             diffusiveDensity = diffusiveDensity.multiply(alt.negate().add(zmho).divide(zsht).exp().subtract(1).multiply(-zsht).divide(zsho).exp());
  2845.             setDensity(ANOMALOUS_OXYGEN, diffusiveDensity);

  2846.             // Convert densities from cm-3 to m-3
  2847.             for (int i = 0; i < 9; i++) {
  2848.                 setDensity(i, getDensity(i).multiply(1.0e+06));
  2849.             }

  2850.             /**** Total mass density ****/
  2851.             final T tmd =     getDensity(HELIUM)            .multiply(HE_MASS).
  2852.                           add(getDensity(ATOMIC_OXYGEN)     .multiply( O_MASS)).
  2853.                           add(getDensity(MOLECULAR_NITROGEN).multiply(N2_MASS)).
  2854.                           add(getDensity(MOLECULAR_OXYGEN)  .multiply(O2_MASS)).
  2855.                           add(getDensity(ARGON)             .multiply(AR_MASS)).
  2856.                           add(getDensity(HYDROGEN)          .multiply( H_MASS)).
  2857.                           add(getDensity(ATOMIC_NITROGEN)   .multiply( N_MASS)).
  2858.                           multiply(AMU);
  2859.             setDensity(TOTAL_MASS, tmd);

  2860.         }

  2861.         /** Calculate temperatures and densities not including anomalous oxygen.
  2862.          *  <p>NOTES ON INPUT VARIABLES:<br>
  2863.          *  Seconds, Local Time, and Longitude are used independently in the
  2864.          *  model and are not of equal importance for every situation.<br>
  2865.          *  For the most physically realistic calculation these three
  2866.          *  variables should be consistent (lst=sec/3600 + lon/15).<br>
  2867.          *  The Equation of Time departures from the above formula
  2868.          *  for apparent local time can be included if available but
  2869.          *  are of minor importance.<br><br>
  2870.          *
  2871.          *  f107 and f107A values used to generate the model correspond
  2872.          *  to the 10.7 cm radio flux at the actual distance of the Earth
  2873.          *  from the Sun rather than the radio flux at 1 AU. The following
  2874.          *  site provides both classes of values:<br>
  2875.          *  ftp://ftp.ngdc.noaa.gov/STP/SOLAR_DATA/SOLAR_RADIO/FLUX/<br><br>
  2876.          *
  2877.          *  f107, f107A, and ap effects are neither large nor well established below 80 km
  2878.          *  and these parameters should be set to 150., 150., and 4. respectively.
  2879.          *  </p>
  2880.          *  @param alt altitude (km)
  2881.          */
  2882.         void gtd7(final T alt) {

  2883.             // Calculates for thermosphere/mesosphere (above ZN2[0])
  2884.             final T altt = (alt.getReal() > ZN2[0]) ? alt : zero.add(ZN2[0]);
  2885.             gts7(altt);
  2886.             if (alt.getReal() >= ZN2[0]) {
  2887.                 return;
  2888.             }

  2889.             // Calculates for lower mesosphere/upper stratosphere (between ZN2[0] and ZN3[0]):
  2890.             // Temperature at nodes and gradients at end nodes
  2891.             // Inverse temperature a linear function of spherical harmonics
  2892.             final double r = PMA[2][0] * PAVGM[2];
  2893.             meso_tgn2[0] = meso_tgn1[1];
  2894.             meso_tn2[0]  = meso_tn1[4];
  2895.             meso_tn2[1]  = glob7s(PMA[0]).multiply(sw[20]         ).negate().add(1).reciprocal().multiply(PMA[0][0] * PAVGM[0]);
  2896.             meso_tn2[2]  = glob7s(PMA[1]).multiply(sw[20]         ).negate().add(1).reciprocal().multiply(PMA[1][0] * PAVGM[1]);
  2897.             meso_tn2[3]  = glob7s(PMA[2]).multiply(sw[20] * sw[22]).negate().add(1).reciprocal().multiply(PMA[2][0] * PAVGM[2]);
  2898.             meso_tgn2[1] = glob7s(PMA[9]).multiply(sw[20] * sw[22]).add(1).multiply(PMA[9][0] * PAVGM[8]).
  2899.                            multiply(meso_tn2[3]).multiply(meso_tn2[3]).divide(r * r);
  2900.             meso_tn3[0]  = meso_tn2[3];

  2901.             // Calculates for lower stratosphere and troposphere (below ZN3[0])
  2902.             // Temperature at nodes and gradients at end nodes
  2903.             // Inverse temperature a linear function of spherical harmonics
  2904.             if (alt.getReal() < ZN3[0]) {
  2905.                 final double q = PMA[6][0] * PAVGM[6];
  2906.                 meso_tgn3[0] = meso_tgn2[1];
  2907.                 meso_tn3[1]  = glob7s(PMA[3]).multiply(sw[22]).negate().add(1).reciprocal().multiply(PMA[3][0] * PAVGM[3]);
  2908.                 meso_tn3[2]  = glob7s(PMA[4]).multiply(sw[22]).negate().add(1).reciprocal().multiply(PMA[4][0] * PAVGM[4]);
  2909.                 meso_tn3[3]  = glob7s(PMA[5]).multiply(sw[22]).negate().add(1).reciprocal().multiply(PMA[5][0] * PAVGM[5]);
  2910.                 meso_tn3[4]  = glob7s(PMA[6]).multiply(sw[22]).negate().add(1).reciprocal().multiply(PMA[6][0] * PAVGM[6]);
  2911.                 meso_tgn3[1] = glob7s(PMA[7]).multiply(sw[22])         .add(1).multiply(PMA[7][0] * PAVGM[7]).
  2912.                                multiply(meso_tn3[4]).multiply(meso_tn3[4]).divide(q * q);

  2913.             }

  2914.             // Linear transition to full mixing below ZN2[0]
  2915.             final T dmc = (alt.getReal() > ZMIX) ?
  2916.                            alt.subtract(ZN2[0]).divide(ZN2[0] - ZMIX).add(1) :
  2917.                            zero;
  2918.             final T dz28 = getDensity(MOLECULAR_NITROGEN);

  2919.             // N2 density
  2920.             final T dm28m = dm28.multiply(1.0e+06);
  2921.             T dmr = dz28.divide(dm28m).subtract(1);
  2922.             T dst = densm(alt, dm28m, PDM[2][4]).multiply(dmr.multiply(dmc).add(1));
  2923.             setDensity(MOLECULAR_NITROGEN, dst);

  2924.             // HE density
  2925.             dmr = getDensity(HELIUM).divide(dz28.multiply(PDM[0][1])).subtract(1);
  2926.             dst = getDensity(MOLECULAR_NITROGEN).multiply(PDM[0][1]).multiply(dmr.multiply(dmc).add(1));
  2927.             setDensity(HELIUM, dst);

  2928.             // O density
  2929.             setDensity(ATOMIC_OXYGEN, zero);
  2930.             setDensity(ANOMALOUS_OXYGEN, zero);

  2931.             // O2 density
  2932.             dmr = getDensity(MOLECULAR_OXYGEN).divide(dz28.multiply(PDM[3][1])).subtract(1);
  2933.             dst = getDensity(MOLECULAR_NITROGEN).multiply(PDM[3][1]).multiply(dmr.multiply(dmc).add(1));
  2934.             setDensity(MOLECULAR_OXYGEN, dst);

  2935.             // AR density
  2936.             dmr = getDensity(ARGON).divide(dz28.multiply(PDM[4][1])).subtract(1);
  2937.             dst = getDensity(MOLECULAR_NITROGEN).multiply(PDM[4][1]).multiply(dmr.multiply(dmc).add(1));
  2938.             setDensity(ARGON, dst);

  2939.             // H density
  2940.             setDensity(HYDROGEN, zero);

  2941.             // N density
  2942.             setDensity(ATOMIC_NITROGEN, zero);

  2943.             // Total mass density
  2944.             final T tmd =       getDensity(HELIUM)            .multiply(HE_MASS).
  2945.                             add(getDensity(ATOMIC_OXYGEN)     .multiply( O_MASS)).
  2946.                             add(getDensity(MOLECULAR_NITROGEN).multiply(N2_MASS)).
  2947.                             add(getDensity(MOLECULAR_OXYGEN)  .multiply(O2_MASS)).
  2948.                             add(getDensity(ARGON)             .multiply(AR_MASS)).
  2949.                             add(getDensity(HYDROGEN)          .multiply( H_MASS)).
  2950.                             add(getDensity(ATOMIC_NITROGEN)   .multiply( N_MASS)).
  2951.                             multiply(AMU);
  2952.             setDensity(TOTAL_MASS, tmd);

  2953.             // Temperature at altitude
  2954.             setTemperature(ALTITUDE, densm(alt, field.getOne(), 0));

  2955.         }

  2956.         /** Calculate temperatures and densities including anomalous oxygen.
  2957.          *  <p></p>
  2958.          *  <p>NOTES ON INPUT VARIABLES:<br>
  2959.          *  Seconds, Local Time, and Longitude are used independently in the
  2960.          *  model and are not of equal importance for every situation.<br>
  2961.          *  For the most physically realistic calculation these three
  2962.          *  variables should be consistent (lst=sec/3600 + lon/15).<br>
  2963.          *  The Equation of Time departures from the above formula
  2964.          *  for apparent local time can be included if available but
  2965.          *  are of minor importance.<br>
  2966.          *  <br>
  2967.          *  f107 and f107A values used to generate the model correspond
  2968.          *  to the 10.7 cm radio flux at the actual distance of the Earth
  2969.          *  from the Sun rather than the radio flux at 1 AU. The following
  2970.          *  site provides both classes of values:<br>
  2971.          *  ftp://ftp.ngdc.noaa.gov/STP/SOLAR_DATA/SOLAR_RADIO/FLUX/<br>
  2972.          *  <br>
  2973.          *  f107, f107A, and ap effects are neither large nor well established below 80 km
  2974.          *  and these parameters should be set to 150., 150., and 4. respectively.
  2975.          *  </p>
  2976.          *  @param alt altitude (km)
  2977.          */
  2978.         void gtd7d(final T alt) {

  2979.             // Compute densities and temperatures
  2980.             gtd7(alt);

  2981.             // Update the total mass density with anomalous oxygen contribution
  2982.             final T dTot = getDensity(TOTAL_MASS).add(getDensity(ANOMALOUS_OXYGEN).multiply( AMU * O_MASS));
  2983.             setDensity(TOTAL_MASS, dTot);

  2984.         }

  2985.         /** Set one density.
  2986.          * @param index one of the nine elements :
  2987.          * <ul>
  2988.          * <li>{@link #HELIUM}</li>
  2989.          * <li>{@link #ATOMIC_OXYGEN}</li>
  2990.          * <li>{@link #MOLECULAR_NITROGEN}</li>
  2991.          * <li>{@link #MOLECULAR_OXYGEN}</li>
  2992.          * <li>{@link #ARGON}</li>
  2993.          * <li>{@link #TOTAL_MASS}</li>
  2994.          * <li>{@link #HYDROGEN}</li>
  2995.          * <li>{@link #ATOMIC_NITROGEN}</li>
  2996.          * <li>{@link #ATOMIC_NITROGEN}</li>
  2997.          * </ul>
  2998.          * @param d the value of density to set
  2999.          */
  3000.         void setDensity(final int index, final T d) {
  3001.             densities[index] = d;
  3002.         }

  3003.         /** Set one temperature.
  3004.          * @param index one of the two elements :
  3005.          * <ul>
  3006.          * <li>{@link #EXOSPHERIC}</li>
  3007.          * <li>{@link #ALTITUDE}</li>
  3008.          * </ul>
  3009.          * @param t the value of temperature to set
  3010.          */
  3011.         void setTemperature(final int index, final T t) {
  3012.             temperatures[index] = t;
  3013.         }

  3014.         /** Get one of the stored densities.
  3015.          * @param index one of the nine elements :
  3016.          * <ul>
  3017.          * <li>{@link #HELIUM}</li>
  3018.          * <li>{@link #ATOMIC_OXYGEN}</li>
  3019.          * <li>{@link #MOLECULAR_NITROGEN}</li>
  3020.          * <li>{@link #MOLECULAR_OXYGEN}</li>
  3021.          * <li>{@link #ARGON}</li>
  3022.          * <li>{@link #TOTAL_MASS}</li>
  3023.          * <li>{@link #HYDROGEN}</li>
  3024.          * <li>{@link #ATOMIC_NITROGEN}</li>
  3025.          * <li>{@link #ATOMIC_NITROGEN}</li>
  3026.          * </ul>
  3027.          * @return the requested density
  3028.          */
  3029.         public T getDensity(final int index) {
  3030.             return densities[index];
  3031.         }

  3032.         /** Calculate G(L) function with upper thermosphere parameters.
  3033.          *  @param p array of parameters
  3034.          *  @return G(L) value
  3035.          */
  3036.         private T globe7(final double[] p) {

  3037.             final T[] t = MathArrays.buildArray(field, 14);
  3038.             final double cd32 = FastMath.cos(DAY_TO_RAD * (doy - p[31]));
  3039.             final double cd18 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[17]));
  3040.             final double cd14 = FastMath.cos(DAY_TO_RAD * (doy - p[13]));
  3041.             final double cd39 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[38]));

  3042.             // F10.7 effect
  3043.             final double df  = f107  - f107a;
  3044.             final double dfa = f107a - FLUX_REF;
  3045.             t[0] = zero.add(p[19] * df * (1.0 + p[59] * dfa) +
  3046.                             p[20] * df * df +
  3047.                             p[21] * dfa +
  3048.                             p[29] * dfa * dfa);

  3049.             final double f1 = 1.0 + (p[47] * dfa + p[19] * df + p[20] * df * df) * swc[1];
  3050.             final double f2 = 1.0 + (p[49] * dfa + p[19] * df + p[20] * df * df) * swc[1];

  3051.             // Time independent
  3052.             t[1] =     plg[0][2].multiply(p[ 1]).
  3053.                    add(plg[0][4].multiply(p[ 2])).
  3054.                    add(plg[0][6].multiply(p[22])).
  3055.                    add(plg[0][2].multiply(p[14] * dfa * swc[1])).
  3056.                    add(plg[0][1].multiply(p[26]));

  3057.             // Symmetrical annual
  3058.             t[2] = zero.add(p[18] * cd32);

  3059.             // Symmetrical semiannual
  3060.             t[3] = plg[0][2].multiply(p[16]).add(p[15]).multiply(cd18);

  3061.             // Asymmetrical annual
  3062.             t[4] = plg[0][1].multiply(p[9]).add(plg[0][3].multiply(p[10])).multiply(f1 * cd14);

  3063.             // Asymmetrical semiannual
  3064.             t[5] = plg[0][1].multiply(p[37] * cd39);

  3065.             // Diurnal
  3066.             if (sw[7] != 0) {
  3067.                 final T t71 = plg[1][2].multiply(p[11] * cd14 * swc[5]);
  3068.                 final T t72 = plg[1][2].multiply(p[12] * cd14 * swc[5]);
  3069.                 t[6] =      plg[1][1].multiply(p[3]).add(plg[1][3].multiply(p[4])).add(plg[1][5].multiply(p[27])).add(t71).multiply(ctloc).
  3070.                         add(plg[1][1].multiply(p[6]).add(plg[1][3].multiply(p[7])).add(plg[1][5].multiply(p[28])).add(t72).multiply(stloc)).
  3071.                         multiply(f2);
  3072.             }

  3073.             // Semidiurnal
  3074.             if (sw[8] != 0) {
  3075.                 final T t81 = plg[2][3].multiply(p[23]).add(plg[2][5].multiply(p[35])).multiply(cd14 * swc[5]);
  3076.                 final T t82 = plg[2][3].multiply(p[33]).add(plg[2][5].multiply(p[36])).multiply(cd14 * swc[5]);
  3077.                 t[7] =     plg[2][2].multiply(p[5]).add(plg[2][4].multiply(p[41])).add(t81).multiply(c2tloc).
  3078.                        add(plg[2][2].multiply(p[8]).add(plg[2][4].multiply(p[42])).add(t82).multiply(s2tloc)).
  3079.                        multiply(f2);
  3080.             }

  3081.             // Terdiurnal
  3082.             if (sw[14] != 0) {
  3083.                 t[13] =     plg[3][3].multiply(p[39]).add(plg[3][4].multiply(p[93]).add(plg[3][6].multiply(p[46])).multiply(cd14 * swc[5])).multiply(s3tloc).
  3084.                         add(plg[3][3].multiply(p[40]).add(plg[3][4].multiply(p[94]).add(plg[3][6].multiply(p[48])).multiply(cd14 * swc[5])).multiply(c3tloc)).
  3085.                         multiply(f2);
  3086.             }

  3087.             // magnetic activity based on daily ap
  3088.             if (sw[9] == -1) {
  3089.                 if (p[51] != 0) {
  3090.                     final T exp1 = lat.abs().negate().add(LAT_REF).multiply(p[138]).add(1).
  3091.                                     reciprocal().multiply(-10800.0 * FastMath.abs(p[51])).
  3092.                                     exp();
  3093.                     final double p24 = FastMath.max(p[24], 1.0e-4);
  3094.                     apt = sg0(min(0.99999, exp1), p24, p[25]);
  3095.                     t[8] =      plg[0][2].multiply(p[96]).add(plg[0][4].multiply(p[54])).add(p[50]).
  3096.                            add((plg[0][1].multiply(p[125]).add(plg[0][3].multiply(p[126])).add(plg[0][5].multiply(p[127]))).multiply(cd14 * swc[5])).
  3097.                            add((plg[1][1].multiply(p[128]).add(plg[1][3].multiply(p[129])).add(plg[1][5].multiply(p[130]))).multiply(swc[7]).multiply(hl.subtract(p[131]).multiply(HOUR_TO_RAD).cos())).
  3098.                            multiply(apt);
  3099.                 }
  3100.             } else {
  3101.                 final double apd = ap[0] - 4.0;
  3102.                 final double p44 = (p[43] < 0.) ? 1.0E-5 : p[43];
  3103.                 final double p45 = p[44];
  3104.                 apdf = apd + (p45 - 1.0) * (apd + (FastMath.exp(-p44 * apd) - 1.0) / p44);
  3105.                 if (sw[9] != 0) {
  3106.                     t[8] =      plg[0][2].multiply(p[45]).add(plg[0][4].multiply(p[34])).add(p[32]).
  3107.                            add((plg[0][1].multiply(p[100]).add(plg[0][3].multiply(p[101])).add(plg[0][5].multiply(p[102]))).multiply(cd14 * swc[5])).
  3108.                            add((plg[1][1].multiply(p[121]).add(plg[1][3].multiply(p[122])).add(plg[1][5].multiply(p[123]))).multiply(swc[7]).multiply(hl.subtract(p[124]).multiply(HOUR_TO_RAD).cos())).
  3109.                            multiply(apdf);
  3110.                 }
  3111.             }

  3112.             if (sw[10] != 0) {
  3113.                 final T lonr = lon.multiply(DEG_TO_RAD);
  3114.                 // Longitudinal
  3115.                 if (sw[11] != 0) {
  3116.                     t[10] =         plg[1][2].multiply(p[ 64]) .add(plg[1][4].multiply(p[ 65])).add(plg[1][6].multiply(p[ 66])).
  3117.                                 add(plg[1][1].multiply(p[103])).add(plg[1][3].multiply(p[104])).add(plg[1][5].multiply(p[105])).
  3118.                                 add((plg[1][1].multiply(p[109])).add(plg[1][3].multiply(p[110])).add(plg[1][5].multiply(p[111])).multiply(swc[5] * cd14)).
  3119.                                 multiply(lonr.cos()).
  3120.                             add(    plg[1][2].multiply(p[ 90]) .add(plg[1][4].multiply(p[ 91])).add(plg[1][6].multiply(p[ 92])).
  3121.                                 add(plg[1][1].multiply(p[106])).add(plg[1][3].multiply(p[107])).add(plg[1][5].multiply(p[108])).
  3122.                                 add((plg[1][1].multiply(p[112])).add(plg[1][3].multiply(p[113])).add(plg[1][5].multiply(p[114])).multiply(swc[5] * cd14)).
  3123.                                 multiply(lonr.sin())).
  3124.                             multiply(1.0 + p[80] * dfa * swc[1]);
  3125.                 }

  3126.                 // ut and mixed ut, longitude
  3127.                 if (sw[12] != 0) {
  3128.                     t[11] =          plg[0][1].multiply(p[95]).add(1).multiply(1.0 + p[81] * dfa * swc[1]).
  3129.                             multiply(plg[0][1].multiply(p[119] * swc[5] * cd14).add(1)).
  3130.                             multiply(plg[0][1].multiply(p[68]).add(plg[0][3].multiply(p[69])).add(plg[0][5].multiply(p[70]))).
  3131.                             multiply(sec.subtract(p[71]).multiply(SEC_TO_RAD).cos());
  3132.                     t[11] = t[11].
  3133.                             add(plg[2][3].multiply(p[76]).add(plg[2][5].multiply(p[77])).add(plg[2][7].multiply(p[78])).
  3134.                                 multiply(swc[11] * (1.0 + p[137] * dfa * swc[1])).
  3135.                                 multiply(sec.subtract(p[79]).multiply(SEC_TO_RAD).add(lonr.multiply(2)).cos()));
  3136.                 }

  3137.                 /* ut, longitude magnetic activity */
  3138.                 if (sw[13] != 0) {
  3139.                     if (sw[9] == -1) {
  3140.                         if (p[51] != 0.) {
  3141.                             t[12] = apt.multiply(swc[11]).multiply(plg[0][1].multiply(p[132]).add(1)).
  3142.                                     multiply(plg[1][2].multiply(p[52]).add(plg[1][4].multiply(p[98])).add(plg[1][6].multiply(p[67]))).
  3143.                                     multiply(lon.subtract(p[97]).multiply(DEG_TO_RAD).cos()).
  3144.                                     add(apt.multiply(swc[11] * swc[5] * cd14).
  3145.                                         multiply(plg[1][1].multiply(p[133]).add(plg[1][3].multiply(p[134])).add(plg[1][5].multiply(p[135]))).
  3146.                                         multiply(lon.subtract(p[136]).multiply(DEG_TO_RAD).cos())).
  3147.                                     add(apt.multiply(swc[12]).
  3148.                                         multiply(plg[0][1].multiply(p[55]).add(plg[0][3].multiply(p[56])).add(plg[0][5].multiply(p[57]))).
  3149.                                         multiply(sec.subtract(p[58]).multiply(SEC_TO_RAD).cos()));
  3150.                         }
  3151.                     } else {
  3152.                         t[12] = plg[0][1].multiply(p[120]).add(1).multiply(apdf * swc[11]).
  3153.                                 multiply(plg[1][2].multiply(p[60]).add(plg[1][4].multiply(p[61])).add(plg[1][6].multiply(p[62]))).
  3154.                                 multiply(lon.subtract(p[63]).multiply(DEG_TO_RAD).cos()).
  3155.                                 add(plg[1][1].multiply(p[115]).add(plg[1][3].multiply(p[116])).add(plg[1][5].multiply(p[117])).
  3156.                                     multiply(apdf * swc[11] * swc[5] * cd14).
  3157.                                     multiply(lon.subtract(p[118]).multiply(DEG_TO_RAD).cos())).
  3158.                                 add(plg[0][1].multiply(p[83]).add(plg[0][3].multiply(p[84])).add(plg[0][5].multiply(p[85])).
  3159.                                     multiply(apdf * swc[12]).
  3160.                                     multiply(sec.subtract(p[75]).multiply(SEC_TO_RAD).cos()));
  3161.                     }
  3162.                 }
  3163.             }

  3164.             // Sum all effects (params not used: 82, 89, 99, 139-149)
  3165.             T tinf = zero.add(p[30]);
  3166.             for (int i = 0; i < 14; i++) {
  3167.                 tinf = tinf.add(t[i].multiply(FastMath.abs(sw[i + 1])));
  3168.             }

  3169.             // Return G(L)
  3170.             return tinf;

  3171.         }

  3172.         /** Calculate G(L) function with lower atmosphere parameters.
  3173.          *  @param p array of parameters
  3174.          *  @return G(L) value
  3175.          */
  3176.         private T glob7s(final double[] p) {

  3177.             final T[] t = MathArrays.buildArray(field, 14);
  3178.             final double cd32 = FastMath.cos(DAY_TO_RAD * (doy - p[31]));
  3179.             final double cd18 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[17]));
  3180.             final double cd14 = FastMath.cos(DAY_TO_RAD * (doy - p[13]));
  3181.             final double cd39 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[38]));

  3182.             // F10.7 effect
  3183.             t[0] = zero.add(p[21] * (f107a - FLUX_REF));

  3184.             // Time independent
  3185.             t[1] =     plg[0][2].multiply(p[1]).
  3186.                    add(plg[0][4].multiply(p[2])).
  3187.                    add(plg[0][6].multiply(p[22])).
  3188.                    add(plg[0][1].multiply(p[26])).
  3189.                    add(plg[0][3].multiply(p[14])).
  3190.                    add(plg[0][5].multiply(p[59]));

  3191.             // Symmetrical annual
  3192.             t[2] = plg[0][2].multiply(p[47]).add(plg[0][4].multiply(p[29])).add(p[18]).multiply(cd32);

  3193.             // Symmetrical semiannual
  3194.             t[3] = plg[0][2].multiply(p[16]).add(plg[0][4].multiply(p[30])).add(p[15]).multiply(cd18);

  3195.             // Asymmetrical annual
  3196.             t[4] = plg[0][1].multiply(p[9]).add(plg[0][3].multiply(p[10])).add(plg[0][5].multiply(p[20])).multiply(cd14);

  3197.             // Asymmetrical semiannual
  3198.             t[5] = plg[0][1].multiply(p[37]).multiply(cd39);

  3199.             // Diurnal
  3200.             if (sw[7] != 0) {
  3201.                 final T t71 = plg[1][2].multiply(p[11]).multiply(cd14 * swc[5]);
  3202.                 final T t72 = plg[1][2].multiply(p[12]).multiply(cd14 * swc[5]);
  3203.                 t[6] =     plg[1][1].multiply(p[3]).add(plg[1][3].multiply(p[4])).add(t71).multiply(ctloc).
  3204.                        add(plg[1][1].multiply(p[6]).add(plg[1][3].multiply(p[7])).add(t72).multiply(stloc));
  3205.             }

  3206.             // Semidiurnal
  3207.             if (sw[8] != 0) {
  3208.                 final T t81 = plg[2][3].multiply(p[23]).add(plg[2][5].multiply(p[35])).multiply(cd14 * swc[5]);
  3209.                 final T t82 = plg[2][3].multiply(p[33]).add(plg[2][5].multiply(p[36])).multiply(cd14 * swc[5]);
  3210.                 t[7] =     plg[2][2].multiply(p[5]).add(plg[2][4].multiply(p[41])).add(t81).multiply(c2tloc).
  3211.                        add(plg[2][2].multiply(p[8]).add(plg[2][4].multiply(p[42])).add(t82).multiply(s2tloc));
  3212.             }

  3213.             // Terdiurnal
  3214.             if (sw[14] != 0) {
  3215.                 t[13] = plg[3][3].multiply(p[39]).multiply(s3tloc).add(plg[3][3].multiply(p[40]).multiply(c3tloc));
  3216.             }

  3217.             // Magnetic activity
  3218.             if (sw[9] == 1) {
  3219.                 t[8] = plg[0][2].multiply(p[45] * swc[2]).add(p[32]).multiply(apdf);
  3220.             } else if (sw[9] == -1) {
  3221.                 t[8] = plg[0][2].multiply(p[96] * swc[2]).add(p[50]).multiply(apt);
  3222.             }

  3223.             // Longitudinal
  3224.             if (!(sw[10] == 0 || sw[11] == 0)) {
  3225.                 final T lonr = lon.multiply(DEG_TO_RAD);
  3226.                 t[10] = plg[0][1].multiply(p[80] * swc[5] * FastMath.cos(DAY_TO_RAD * (doy - p[81])) +
  3227.                                            p[85] * swc[6] * FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[86]))).
  3228.                        add(1.0 +
  3229.                            p[83] * swc[3] * FastMath.cos(DAY_TO_RAD * (doy - p[84])) +
  3230.                            p[87] * swc[4] * FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[88]))).
  3231.                        multiply(    plg[1][2].multiply(p[64]).
  3232.                                 add(plg[1][4].multiply(p[65])).
  3233.                                 add(plg[1][6].multiply(p[66])).
  3234.                                 add(plg[1][1].multiply(p[74])).
  3235.                                 add(plg[1][3].multiply(p[75])).
  3236.                                 add(plg[1][5].multiply(p[76])).multiply(lonr.cos()).
  3237.                           add(      plg[1][2].multiply(p[90]).
  3238.                                 add(plg[1][4].multiply(p[91])).
  3239.                                 add(plg[1][6].multiply(p[92])).
  3240.                                 add(plg[1][1].multiply(p[77])).
  3241.                                 add(plg[1][3].multiply(p[78])).
  3242.                                 add(plg[1][5].multiply(p[79])).multiply(lonr.sin())));
  3243.             }

  3244.             // Sum all effects
  3245.             T gl = zero;
  3246.             for (int i = 0; i < 14; i++) {
  3247.                 gl = gl.add(t[i].multiply(FastMath.abs(sw[i + 1])));
  3248.             }

  3249.             // Return G(L)
  3250.             return gl;
  3251.         }

  3252.         /** Implements sg0 function (Eq. A24a).
  3253.          * @param ex ex
  3254.          * @param p24 abs(p[24])
  3255.          * @param p25 p[25]
  3256.          * @return sg0
  3257.          */
  3258.         private T sg0(final T ex, final double p24, final double p25) {
  3259.             final double g01 = g0(ap[1], p24, p25);
  3260.             final double g02 = g0(ap[2], p24, p25);
  3261.             final double g03 = g0(ap[3], p24, p25);
  3262.             final double g04 = g0(ap[4], p24, p25);
  3263.             final double g05 = g0(ap[5], p24, p25);
  3264.             final double g06 = g0(ap[6], p24, p25);
  3265.             final T ex2      = ex.multiply(ex);
  3266.             final T ex3      = ex.multiply(ex2);
  3267.             final T ex4      = ex2.multiply(ex2);
  3268.             final T ex8      = ex4.multiply(ex4);
  3269.             final T ex12     = ex4.multiply(ex8);
  3270.             final T g234     = ex.multiply(g02).add(ex2.multiply(g03)).add(ex3.multiply(g04));
  3271.             final T g56      = ex4.multiply(g05).add(ex12.multiply(g06));
  3272.             final T ex19     = ex3.multiply(ex4).multiply(ex12);
  3273.             final T omex     = ex.negate().add(1);
  3274.             final T sumex    = ex19.negate().add(1).divide(omex).multiply(ex.sqrt()).add(1);
  3275.             return ex8.negate().add(1).multiply(g56).divide(omex).add(g234).add(g01).divide(sumex);
  3276.         }

  3277.         /** Implements go function (Eq. A24d).
  3278.          * @param apI 3 hrs ap
  3279.          * @param p24 abs(p[24])
  3280.          * @param p25 p[25]
  3281.          * @return go
  3282.          */
  3283.         private double g0(final double apI, final double p24, final double p25) {
  3284.             final double am4 = apI - 4.0;
  3285.             return am4 + (p25 - 1.0) * (am4 + (FastMath.exp(-p24 * am4) - 1.0) / p24);
  3286.         }

  3287.         /** Calculates chemistry/dissociation correction for MSIS models.
  3288.          * @param alt altitude
  3289.          * @param r target ratio
  3290.          * @param h1 transition scale length
  3291.          * @param zh altitude of 1/2 R
  3292.          * @return correction
  3293.          */
  3294.         private T ccor(final T alt, final T r, final double h1, final double zh) {
  3295.             final T e = alt.subtract(zh).divide(h1);
  3296.             if (e.getReal() > 70.) {
  3297.                 return field.getOne();
  3298.             } else if (e.getReal() < -70.) {
  3299.                 return r.exp();
  3300.             } else {
  3301.                 return r.divide(e.exp().add(1)).exp();
  3302.             }
  3303.         }


  3304.         /** Calculates O & O2 chemistry/dissociation correction for MSIS models.
  3305.          * @param alt altitude
  3306.          * @param r target ratio
  3307.          * @param h1 transition scale length
  3308.          * @param zh altitude of 1/2 R
  3309.          * @param h2 transition scale length
  3310.          * @return correction
  3311.          */
  3312.         private T ccor2(final T alt, final double r, final double h1, final double zh, final double h2) {
  3313.             final T e1 = alt.subtract(zh).divide(h1);
  3314.             final T e2 = alt.subtract(zh).divide(h2);
  3315.             if ((e1.getReal() > 70.) || (e2.getReal() > 70.)) {
  3316.                 return field.getOne();
  3317.             } else if ((e1.getReal() < -70.) && (e2.getReal() < -70.)) {
  3318.                 return zero.add(FastMath.exp(r));
  3319.             } else {
  3320.                 final T ex1 = e1.exp();
  3321.                 final T ex2 = e2.exp();
  3322.                 return ex1.add(ex2).multiply(0.5).add(1).reciprocal().multiply(r).exp();
  3323.             }
  3324.         }

  3325.         /** Calculates scale height.
  3326.          * @param alt altitude
  3327.          * @param xm species molecular weight
  3328.          * @param temp temperature
  3329.          * @return scale height (km)
  3330.          */
  3331.         private T scalh(final double alt, final double xm, final double temp) {
  3332.             // Gravity at altitude
  3333.             final T denom = rlat.reciprocal().multiply(alt).add(1);
  3334.             final T galt = glat.divide(denom.multiply(denom));
  3335.             return galt.reciprocal().multiply(R_GAS * temp / xm);
  3336.         }

  3337.         /** Calculates turbopause correction for MSIS models.
  3338.          * @param dd diffusive density
  3339.          * @param dm full mixed density
  3340.          * @param zhm transition scale length
  3341.          * @param xmm full mixed molecular weight
  3342.          * @param xm species molecular weight
  3343.          * @return combined density
  3344.          */
  3345.         private T dnet(final T dd, final T dm, final double zhm, final double xmm, final double xm) {
  3346.             if (!(dm.getReal() > 0 && dd.getReal() > 0)) {
  3347.                 T ddd = dd;
  3348.                 if (dd.getReal() == 0 && dm.getReal() == 0) {
  3349.                     ddd = field.getOne();
  3350.                 }
  3351.                 if (dm.getReal() == 0) {
  3352.                     return ddd;
  3353.                 }
  3354.                 if (dd.getReal() == 0) {
  3355.                     return dm;
  3356.                 }
  3357.             }

  3358.             final double a  = zhm / (xmm - xm);
  3359.             final T ylog = dm.divide(dd).log().multiply(a);
  3360.             if (ylog.getReal() < -10.) {
  3361.                 return dd;
  3362.             } else if (ylog.getReal() > 10.) {
  3363.                 return dm;
  3364.             } else {
  3365.                 return ylog.exp().add(1).pow(1.0 / a).multiply(dd);
  3366.             }
  3367.         }

  3368.         /** Integrate cubic spline function from xa[0] to x.
  3369.          * <p>ADAPTED FROM NUMERICAL RECIPES</p>
  3370.          * @param xa array of abscissas in ascending order
  3371.          * @param ya array of ordinates in ascending order by xa
  3372.          * @param y2a array of second derivatives in ascending order by xa
  3373.          * @param x abscissa end point
  3374.          * @return integral value
  3375.          */
  3376.         private T splini(final T[] xa, final T[] ya, final T[] y2a, final T x) {
  3377.             final int n = xa.length;
  3378.             T yi = zero;
  3379.             int klo = 0;
  3380.             int khi = 1;
  3381.             while (x.getReal() > xa[klo].getReal() && khi < n) {
  3382.                 T xx = x;
  3383.                 if (khi < n - 1) {
  3384.                     xx = (x.getReal() < xa[khi].getReal()) ? x : xa[khi];
  3385.                 }
  3386.                 final T h = xa[khi].subtract(xa[klo]);
  3387.                 final T a = xa[khi].subtract(xx).divide(h);
  3388.                 final T b = xx.subtract(xa[klo]).divide(h);
  3389.                 final T a2 = a.multiply(a);
  3390.                 final T b2 = b.multiply(b);

  3391.                 final T z =
  3392.                            a2.divide(2).subtract(a2.multiply(a2).add(1).divide(4)).multiply(y2a[klo]).
  3393.                            add(b2.multiply(b2).divide(4).subtract(b2.divide(2)).multiply(y2a[khi]));
  3394.                 yi = yi.add(    a2.negate().add(1).multiply(ya[klo]).divide(2).
  3395.                             add(b2.multiply(ya[khi]).divide(2)).
  3396.                             add(z.multiply(h).multiply(h).divide(6)).
  3397.                             multiply(h));
  3398.                 klo++;
  3399.                 khi++;
  3400.             }
  3401.             return yi;
  3402.         }

  3403.         /** Calculate cubic spline interpolated value.
  3404.          * <p>ADAPTED FROM NUMERICAL RECIPES</p>
  3405.          * @param xa array of abscissas in ascending order
  3406.          * @param ya array of ordinates in ascending order by xa
  3407.          * @param y2a array of second derivatives in ascending order by xa
  3408.          * @param x abscissa for interpolation
  3409.          * @return interpolated value
  3410.          */
  3411.         private T splint(final T[] xa, final T[] ya, final T[] y2a, final T x) {
  3412.             final int n = xa.length;
  3413.             int klo = 0;
  3414.             int khi = n - 1;
  3415.             while (khi - klo > 1) {
  3416.                 final int k = (khi + klo) >>> 1;
  3417.                 if (xa[k].getReal() > x.getReal()) {
  3418.                     khi = k;
  3419.                 } else {
  3420.                     klo = k;
  3421.                 }
  3422.             }
  3423.             final T h = xa[khi].subtract(xa[klo]);
  3424.             final T a = xa[khi].subtract(x).divide(h);
  3425.             final T b = x.subtract(xa[klo]).divide(h);
  3426.             return a.multiply(ya[klo]).add(b.multiply(ya[khi])).
  3427.                    add((    a.multiply(a).multiply(a).subtract(a).multiply(y2a[klo]).
  3428.                         add(b.multiply(b).multiply(b).subtract(b).multiply(y2a[khi]))
  3429.                        ).multiply(h).multiply(h).divide(6));
  3430.         }

  3431.         /** Calculate 2nd derivatives of cubic spline interpolation function.
  3432.          * <p>ADAPTED FROM NUMERICAL RECIPES</p>
  3433.          * @param x array of abscissas in ascending order
  3434.          * @param y array of ordinates in ascending order by x
  3435.          * @param yp1 derivative at x[0] (2nd derivatives null if > 1E30)
  3436.          * @param ypn derivative at x[n-1] (2nd derivatives null if > 1E30)
  3437.          * @return array of second derivatives
  3438.          */
  3439.         private T[] spline(final T[] x, final T[] y, final T yp1, final T ypn) {
  3440.             final int n = x.length;
  3441.             final T[] y2 = MathArrays.buildArray(field, n);
  3442.             final T[] u  = MathArrays.buildArray(field, n);

  3443.             if (yp1.getReal() < 1e+30) {
  3444.                 y2[0] = zero.add(-0.5);
  3445.                 final T dx = x[1].subtract(x[0]);
  3446.                 final T dy = y[1].subtract(y[0]);
  3447.                 u[0]  = dx.reciprocal().multiply(3.0).multiply(dy.divide(dx).subtract(yp1));
  3448.             }
  3449.             for (int i = 1; i < n - 1; i++) {
  3450.                 final T dx0m = x[i].subtract(x[i - 1]);
  3451.                 final T dy0m = y[i].subtract(y[i - 1]);
  3452.                 final T dxpm = x[i + 1].subtract(x[i - 1]);
  3453.                 final T dxp0 = x[i + 1].subtract(x[i]);
  3454.                 final T dyp0 = y[i + 1].subtract(y[i]);
  3455.                 final T sig = dx0m.divide(dxpm);
  3456.                 final T p = sig.multiply(y2[i - 1]).add(2.0);
  3457.                 y2[i] = sig.subtract(1.0).divide(p);
  3458.                 u[i] = dyp0.divide(dxp0).subtract(dy0m.divide(dx0m)).multiply(6).divide(dxpm).subtract(sig.multiply(u[i - 1])).divide(p);
  3459.             }

  3460.             double qn = 0;
  3461.             T un = zero;
  3462.             if (ypn.getReal() < 1e+30) {
  3463.                 final T dx12 = x[n - 1].subtract(x[n - 2]);
  3464.                 final T dy12 = y[n - 1].subtract(y[n - 2]);
  3465.                 qn = 0.5;
  3466.                 un = dx12.reciprocal().multiply(3.0).multiply(ypn.subtract(dy12.divide(dx12)));
  3467.             }

  3468.             y2[n - 1] = un.subtract(u[n - 2].multiply(qn)).divide(y2[n - 2].multiply(qn).add(1.0));
  3469.             for (int k = n - 2; k >= 0; k--) {
  3470.                 y2[k] = y2[k].multiply(y2[k + 1]).add(u[k]);
  3471.             }

  3472.             return y2;

  3473.         }

  3474.         /** Calculate Temperature and Density Profiles for lower atmosphere.
  3475.          * @param alt altitude
  3476.          * @param d0 density
  3477.          * @param xm mixed density
  3478.          * @return temperature or density profile
  3479.          */
  3480.         private T densm(final T alt, final T d0, final double xm) {

  3481.             T densm = d0;

  3482.             // stratosphere/mesosphere temperature
  3483.             int mn = ZN2.length;
  3484.             T z = (alt.getReal() > ZN2[mn - 1]) ? alt : zero.add(ZN2[mn - 1]);

  3485.             double z1 = ZN2[0];
  3486.             double z2 = ZN2[mn - 1];
  3487.             T t1 = meso_tn2[0];
  3488.             T t2 = meso_tn2[mn - 1];
  3489.             T zg  = zeta(z, z1);
  3490.             T zgdif = zeta(zero.add(z2), z1);

  3491.             /* set up spline nodes */
  3492.             T[] xs = MathArrays.buildArray(field, mn);
  3493.             T[] ys = MathArrays.buildArray(field, mn);
  3494.             for (int k = 0; k < mn; k++) {
  3495.                 xs[k] = zeta(zero.add(ZN2[k]), z1).divide(zgdif);
  3496.                 ys[k] = meso_tn2[k].reciprocal();
  3497.             }
  3498.             final T qSM = rlat.add(z2).divide(rlat.add(z1));
  3499.             T yd1 = meso_tgn2[0].negate().divide(t1.multiply(t1)).multiply(zgdif);
  3500.             T yd2 = meso_tgn2[1].negate().divide(t2.multiply(t2)).multiply(zgdif).multiply(qSM).multiply(qSM);

  3501.             /* calculate spline coefficients */
  3502.             T[] y2out = spline(xs, ys, yd1, yd2);
  3503.             T x = zg.divide(zgdif);
  3504.             T y = splint(xs, ys, y2out, x);

  3505.             /* temperature at altitude */
  3506.             T tz = y.reciprocal();

  3507.             if (xm != 0.0) {
  3508.                 /* calculate stratosphere / mesospehere density */
  3509.                 final T glb  = galt(zero.add(z1));
  3510.                 final T gamm = glb.multiply(zgdif).multiply(xm / R_GAS);

  3511.                 /* Integrate temperature profile */
  3512.                 final T yi = splini(xs, ys, y2out, x);
  3513.                 final T expl = min(50., gamm.multiply(yi));

  3514.                 /* Density at altitude */
  3515.                 densm = densm.multiply(t1.divide(tz).multiply(expl.negate().exp()));
  3516.             }

  3517.             if (alt.getReal() > ZN3[0]) {
  3518.                 return (xm == 0.0) ? tz : densm;
  3519.             }

  3520.             // troposhere/stratosphere temperature
  3521.             z = alt;
  3522.             mn = ZN3.length;
  3523.             z1 = ZN3[0];
  3524.             z2 = ZN3[mn - 1];
  3525.             t1 = meso_tn3[0];
  3526.             t2 = meso_tn3[mn - 1];
  3527.             zg = zeta(z, z1);
  3528.             zgdif = zeta(zero.add(z2), z1);

  3529.             /* set up spline nodes */
  3530.             xs = MathArrays.buildArray(field, mn);
  3531.             ys = MathArrays.buildArray(field, mn);
  3532.             for (int k = 0; k < mn; k++) {
  3533.                 xs[k] = zeta(zero.add(ZN3[k]), z1).divide(zgdif);
  3534.                 ys[k] = meso_tn3[k].reciprocal();
  3535.             }
  3536.             final T qTS = rlat.add(z2) .divide(rlat.add(z1));
  3537.             yd1 = meso_tgn3[0].negate().divide(t1.multiply(t1)).multiply(zgdif);
  3538.             yd2 = meso_tgn3[1].negate().divide(t2.multiply(t2)).multiply(zgdif).multiply(qTS).multiply(qTS);

  3539.             /* calculate spline coefficients */
  3540.             y2out = spline(xs, ys, yd1, yd2);
  3541.             x = zg.divide(zgdif);
  3542.             y = splint(xs, ys, y2out, x);

  3543.             /* temperature at altitude */
  3544.             tz = y.reciprocal();

  3545.             if (xm != 0.0) {
  3546.                 /* calculate tropospheric / stratosphere density */
  3547.                 final T glb = galt(zero.add(z1));
  3548.                 final T gamm = glb.multiply(zgdif).multiply(xm / R_GAS);

  3549.                 /* Integrate temperature profile */
  3550.                 final T yi = splini(xs, ys, y2out, x);
  3551.                 final T expl = min(50., gamm.multiply(yi));

  3552.                 /* Density at altitude */
  3553.                 densm = densm.multiply(t1.divide(tz).multiply(expl.negate().exp()));
  3554.             }

  3555.             return (xm == 0.0) ? tz : densm;
  3556.         }

  3557.         /** Calculate temperature and density profiles according to new lower thermo polynomial.
  3558.          * @param alt altitude
  3559.          * @param dlb density at lower boundary
  3560.          * @param tinf exospheric temperature
  3561.          * @param tlb temperature at lower boundary
  3562.          * @param xm species molecular weight
  3563.          * @param alpha thermal diffusion coefficient
  3564.          * @param zlb altitude of the lower boundary
  3565.          * @param s2 slope
  3566.          * @return temperature or density profile
  3567.          */
  3568.         private T densu(final T alt, final T dlb, final T tinf,
  3569.                         final T tlb, final double xm,  final double alpha,
  3570.                         final double zlb, final T s2) {
  3571.             /* joining altitudes of Bates and spline */
  3572.             T z = (alt.getReal() > ZN1[0]) ? alt : zero.add(ZN1[0]);

  3573.             /* geopotential altitude difference from ZLB */
  3574.             final T zg2 = zeta(z, zlb);

  3575.             /* Bates temperature */
  3576.             final T tt = tinf.subtract(tinf.subtract(tlb).multiply(s2.negate().multiply(zg2).exp()));
  3577.             final T ta = tt;
  3578.             T tz = tt;

  3579.             final int mn = ZN1.length;
  3580.             final T[] xs = MathArrays.buildArray(field, mn);
  3581.             final T[] ys = MathArrays.buildArray(field, mn);
  3582.             T x = zero;
  3583.             T[] y2out =  MathArrays.buildArray(field, mn);
  3584.             T zgdif = zero;
  3585.             if (alt.getReal() < ZN1[0]) {
  3586.                 /* calculate temperature below ZA
  3587.                  * temperature gradient at ZA from Bates profile */
  3588.                 final T p = rlat.add(zlb).divide(rlat.add(ZN1[0]));
  3589.                 final T dta = tinf.subtract(ta).multiply(s2).multiply(p.multiply(p));
  3590.                 meso_tgn1[0] = dta;
  3591.                 meso_tn1[0] = ta;
  3592.                 final T tzn1mn1 = zero.add(ZN1[mn - 1]);
  3593.                 z = (alt.getReal() > ZN1[mn - 1]) ? alt : tzn1mn1;

  3594.                 final T t1 = meso_tn1[0];
  3595.                 final T t2 = meso_tn1[mn - 1];
  3596.                 /* geopotental difference from z1 */
  3597.                 final T zg = zeta(z, ZN1[0]);
  3598.                 zgdif = zeta(tzn1mn1, ZN1[0]);
  3599.                 /* set up spline nodes */
  3600.                 for (int k = 0; k < mn; k++) {
  3601.                     xs[k] = zeta(zero.add(ZN1[k]), ZN1[0]).divide(zgdif);
  3602.                     ys[k] =  meso_tn1[k].reciprocal();
  3603.                 }
  3604.                 /* end node derivatives */
  3605.                 final T q   = rlat.add(ZN1[mn - 1]).divide(rlat.add(ZN1[0]));
  3606.                 final T yd1 = meso_tgn1[0].negate().divide(t1.multiply(t1)).multiply(zgdif);
  3607.                 final T yd2 = meso_tgn1[1].negate().divide(t2.multiply(t2)).multiply(zgdif).multiply(q.multiply(q));
  3608.                 /* calculate spline coefficients */
  3609.                 y2out = spline(xs, ys, yd1, yd2);
  3610.                 x = zg.divide(zgdif);
  3611.                 final T y = splint(xs, ys, y2out, x);
  3612.                 /* temperature at altitude */
  3613.                 tz = y.reciprocal();
  3614.             }

  3615.             if (xm == 0) {
  3616.                 return tz;
  3617.             }

  3618.             /* calculate density above za */
  3619.             T glb   = galt(zero.add(zlb));
  3620.             T gamma = glb.divide(s2.multiply(tinf)).multiply(xm / R_GAS);
  3621.             T expl = tt.getReal() <= 0 ?
  3622.                      zero.add(50) :
  3623.                      min(50.0, s2.negate().multiply(gamma).multiply(zg2).exp());
  3624.             T densu = dlb.multiply(tlb.divide(tt).pow(gamma.add(alpha + 1))).multiply(expl);

  3625.             /* calculate density below za */
  3626.             if (alt.getReal() < ZN1[0]) {
  3627.                 glb   = galt(zero.add(ZN1[0]));
  3628.                 gamma = glb.multiply(zgdif).multiply(xm / R_GAS);
  3629.                 /* integrate spline temperatures */
  3630.                 expl = tz.getReal() <= 0 ?
  3631.                        zero.add(50.0) :
  3632.                        min(50.0, gamma.multiply(splini(xs, ys, y2out, x)));
  3633.                 /* correct density at altitude */
  3634.                 densu = densu.multiply(meso_tn1[0].divide(tz).pow(alpha + 1).multiply(expl.negate().exp()));
  3635.             }

  3636.             /* Return density at altitude */
  3637.             return densu;
  3638.         }

  3639.         /** Compute min of two values, one double and one field element.
  3640.          * @param d double value
  3641.          * @param f field element
  3642.          * @return min value
  3643.          */
  3644.         private T min(final double d, final T f) {
  3645.             return (f.getReal() > d) ? zero.add(d) : f;
  3646.         }

  3647.         /** Calculate gravity at altitude.
  3648.          * @param alt altitude (km)
  3649.          * @return gravity at altitude (cm/s2)
  3650.          */
  3651.         private T galt(final T alt) {
  3652.             final T r = alt.divide(rlat).add(1);
  3653.             return glat.divide(r.multiply(r));
  3654.         }

  3655.         /** Calculate zeta function.
  3656.          * @param zz zz value
  3657.          * @param zl zl value
  3658.          * @return value of zeta function
  3659.          */
  3660.         private T zeta(final T zz, final double zl) {
  3661.             return zz.subtract(zl).multiply(rlat.add(zl)).divide(rlat.add(zz));
  3662.         }

  3663.     }

  3664. }