PolynomialFieldClockModel.java

/* Copyright 2025-2026 Hawkeye 360 (HE360)
 * Licensed to CS Group (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.time.clocks;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.hipparchus.CalculusFieldElement;
import org.hipparchus.analysis.polynomials.FieldPolynomialFunction;
import org.hipparchus.exception.MathIllegalArgumentException;
import org.hipparchus.exception.NullArgumentException;
import org.hipparchus.util.MathUtils;
import org.orekit.time.FieldAbsoluteDate;

/** Field Polynomial clock model.
 * @param <T> type of the field elements
 * @author Brian Carter
 * @since 14.0
 * @see PolynomialClockModel
 */
public class PolynomialFieldClockModel<T extends CalculusFieldElement<T>> extends AbstractFieldClockModel<T> {

    /** All term. */
    private final List<T> terms;

    /** Simple constructor.
     * @param referenceDate reference date
     * @param terms polynomial terms
     */
    @SafeVarargs
    public PolynomialFieldClockModel(final FieldAbsoluteDate<T> referenceDate,
                                    final T... terms) {
        super(referenceDate);
        this.terms = Arrays.asList(terms);
    }

    /** Get the clock offset at date.
     * @param date date at which offset is requested
     * @return clock offset at specified date
     */
    @Override
    @SuppressWarnings("unchecked")
    public FieldClockOffset<T> getOffset(final FieldAbsoluteDate<T> date) {
        final T dt = date.durationFrom(getReferenceDate());
        final List<T> result = new ArrayList<>(3);
        // Loop over all of the terms in order
        // The value of the first offset is the value of the function at time dt from
        // date
        // The value of the second offset is the derivative of the function at time dt
        // from date
        // Repeat until out of terms
        T[] copyCoefficients = terms.toArray((T[]) new CalculusFieldElement[terms.size()]);
        for (int ii = 0; ii < 3; ii++) {
            final T newValue = value(copyCoefficients, dt);
            result.add(newValue);
            // Take the next derivative
            copyCoefficients = differentiate(copyCoefficients);
        }
        return new FieldClockOffset<>(date, result);
    }


    /** Get the derivative of the given coefficients.
     * @param coefficients the list of provided coefficients
     * @return the differentiated coefficients
     * @throws MathIllegalArgumentException if the derivative is not possible to calculate
     * @throws NullArgumentException if the coefficients is null
     */
    private T[] differentiate(final T[] coefficients) throws MathIllegalArgumentException, NullArgumentException {
        MathUtils.checkNotNull(coefficients);
        final FieldPolynomialFunction<T> func = new FieldPolynomialFunction<>(coefficients);
        final FieldPolynomialFunction<T> derivative = func.polynomialDerivative();
        return derivative.getCoefficients();
    }

    /** Get the value of the function created by the given coeffients.
     * @param coefficients the provided coefficients starting at some degree
     * @param t the time
     * @return the value of the function at that time
     * @throws MathIllegalArgumentException if the derivative is not possible to calculate
     * @throws NullArgumentException if the coefficients are null
     */
    private T value(final T[] coefficients, final T t) throws MathIllegalArgumentException, NullArgumentException {
        MathUtils.checkNotNull(coefficients);
        return new FieldPolynomialFunction<>(coefficients).value(t);

    }
}