IsotropicDragBuilder.java

/* Copyright 2022-2026 Luc Maisonobe
 * 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.forces.drag;

import org.hipparchus.util.FastMath;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.drivers.ParameterDriversSequenceBuilder;

/** Builder for {@link IsotropicDrag} allowing to set coefficients on different time spans.
 * @author Luc Maisonobe
 * @since 14.0
 */
public class IsotropicDragBuilder {

   /** Parameters scaling factor.
     * <p>
     * We use a power of 2 to avoid numeric noise introduction
     * in the multiplications/divisions sequences.
     * </p>
     */
    private static final double SCALE = FastMath.scalb(1.0, -3);

    /** Underlying builder. */
    private final ParameterDriversSequenceBuilder builder;

    /** Cross section (m²). */
    private final double crossSection;

    /** Constructor for an initially empty builder, with min/max set to ±∞.
     * @param crossSection Surface (m²)
     */
    public IsotropicDragBuilder(final double crossSection) {
        this(crossSection, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    }

    /** Constructor for an initially empty builder.
     * <p>
     * The builder {@link #build() build()} method cannot be called right after construction.
     * Some drag coefficients must be set before, either by calling the
     * {@link #addDragCoeff(double) addDragCoeff(dragCoeff)} method once, or by calling the
     * {@link #addDragCoeff(double, AbsoluteDate, AbsoluteDate)
     * addDragCoeff(dragCoeff, earliestValidityDate, latestValidityDate)} method as many times
     * as needed to cover the usage range before the {@link #build() build()} method can be called.
     * </p>
     * @param crossSection Surface (m²)
     * @param dragCoeffMin minimum value of drag coefficient
     * @param dragCoeffMax maximum value of drag coefficient
     */
    public IsotropicDragBuilder(final double crossSection, final double dragCoeffMin, final double dragCoeffMax) {
        this.builder      = new ParameterDriversSequenceBuilder(DragSensitive.DRAG_COEFFICIENT,
                                                                SCALE, dragCoeffMin, dragCoeffMax);
        this.crossSection = crossSection;
    }

    /** Add a coefficient throughout timeline.
     * <p>
     * Calling this method is equivalent to call
     * {@code addDragCoeff(dragCoeff, AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY)}.
     * </p>
     * @param dragCoeff drag coefficient
     * @return the instance itself, allowing use of the fluent interface pattern
     */
    public IsotropicDragBuilder addDragCoeff(final double dragCoeff) {
        builder.addReferenceValue(dragCoeff);
        return this;
    }

    /** Add a coefficient valid for a time span.
     * @param dragCoeff drag coefficient
     * @param earliestValidityDate date after which the coefficient is valid
     * @param latestValidityDate date before which the coefficient is valid
     * @return the instance itself, allowing use of the fluent interface pattern
     */
    public IsotropicDragBuilder addDragCoeff(final double dragCoeff,
                                             final AbsoluteDate earliestValidityDate,
                                             final AbsoluteDate latestValidityDate) {
        builder.addReferenceValue(dragCoeff, earliestValidityDate, latestValidityDate);
        return this;
    }

    /** Build a drag model.
     * <p>
     * If only one coefficient has been set, its name will be {@link DragSensitive#DRAG_COEFFICIENT}.
     * If several coefficients have been set, their names will be built by prepending
     * {@link ParameterDriversSequenceBuilder#SPAN_PREFIX} to {@link DragSensitive#DRAG_COEFFICIENT}
     * and then appending an index counting from 1.
     * </p>
     * @return built model
     */
    public IsotropicDrag build() {
        return new IsotropicDrag(crossSection, builder.build());
    }

}