NbsNrcSteamTable.java

/* Copyright 2002-2024 Thales Alenia Space
 * Licensed to CS Communication & Systèmes (CS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * CS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.orekit.models.earth.weather.water;

import org.hipparchus.CalculusFieldElement;
import org.hipparchus.analysis.interpolation.SplineInterpolator;
import org.hipparchus.analysis.polynomials.PolynomialSplineFunction;
import org.hipparchus.util.FastMath;

/** Steam table from US National Bureau of Standards (NBS) and National Research Council (NRC) of Canada.
 * <p>
 * The table is an extract from table 1 in <a href="https://www.thermopedia.com/content/1150/">Thermopedia</a>,
 * using only the pressure column and truncated to 99°C (the original table goes up to 373.976°C). According to
 * <a href="https://www.thermopedia.com/access/">the access page</a>, this data is available for free.
 * </p>
 * @see <a href="https://dx.doi.org/10.1615/AtoZ.s.steam_tables">Thermopedia Steam Tables</a>
 *
 * @author Luc Maisonobe
 * @since 12.1
 */
public class NbsNrcSteamTable implements WaterVaporPressureProvider {

    /** Celsius temperature offset. */
    private static final double CELSIUS = 273.15;

    /** Minimum temperature of the model, at the triple point of water, i.e. 273.16K (which is 0.01°C). */
    private static final double MIN_T = CELSIUS + 0.01;

    /** Saturation pressure model. */
    private static final PolynomialSplineFunction MODEL;

    static {

        // saturation pressure in SI units (Pa)
        final double[] pressure = {
            00611.73,    657.16,    706.05,    758.13,    813.59,    872.60,    935.37,   1002.09,   1072.97,   1148.25,
            01228.10,   1312.90,   1402.70,   1497.90,   1598.80,   1705.60,   1818.50,   1938.00,   2064.40,   2197.90,
            02338.80,   2487.70,   2644.70,   2810.40,   2985.00,   3169.10,   3362.90,   3567.00,   3781.80,   4007.80,
            04245.50,   4495.30,   4757.80,   5033.50,   5322.90,   5626.70,   5945.40,   6279.50,   6629.80,   6996.90,
            07381.40,   7784.00,   8205.40,   8646.40,   9107.60,   9589.80,  10093.80,  10620.50,  11170.60,  11744.90,
            12344.00,  12970.00,  13623.00,  14303.00,  15012.00,  15752.00,  16522.00,  17324.00,  18159.00,  19028.00,
            19932.00,  20873.00,  21851.00,  22868.00,  23925.00,  25022.00,  26163.00,  27347.00,  28576.00,  29852.00,
            31176.00,  32549.00,  33972.00,  35448.00,  36978.00,  38563.00,  40205.00,  41905.00,  43665.00,  45487.00,
            47373.00,  49324.00,  51342.00,  53428.00,  55585.00,  57815.00,  60119.00,  62499.00,  64958.00,  67496.00,
            70117.00,  72823.00,  75614.00,  78495.00,  81465.00,  84529.00,  87688.00,  90945.00,  94301.00,  97759.00
        };

        // the table first entry is at 0.01°C, not 0.00°C, but remaining entries are 1°C, 2°C, … 99°C
        final double[] temperature = new double[pressure.length];
        for (int i = 0; i < temperature.length; ++i) {
            temperature[i] = (i == 0) ? MIN_T : (CELSIUS + i);
        }

        MODEL = new SplineInterpolator().interpolate(temperature, pressure);

    }

    /** {@inheritDoc} */
    @Override
    public double waterVaporPressure(final double p, final double t, final double rh) {
        return MODEL.value(FastMath.max(t, MIN_T)) * rh;
    }

    /** {@inheritDoc} */
    @Override
    public <T extends CalculusFieldElement<T>> T waterVaporPressure(final T p, final T t, final T rh) {
        return MODEL.value(FastMath.max(t, MIN_T)).multiply(rh);
    }

}