1   /* Copyright 2022-2026 Thales Alenia Space
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.time.clocks;
18  
19  import java.util.List;
20  import java.util.Map;
21  import java.util.stream.Stream;
22  
23  import org.hipparchus.CalculusFieldElement;
24  import org.hipparchus.Field;
25  import org.hipparchus.analysis.differentiation.Gradient;
26  import org.orekit.errors.OrekitException;
27  import org.orekit.errors.OrekitMessages;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.FieldAbsoluteDate;
30  import org.orekit.utils.ImmutableTimeStampedCache;
31  import org.orekit.utils.ParameterDriver;
32  
33  /** Offset clock model backed up by a sample.
34   *
35   * @author Luc Maisonobe
36   * @since 12.1
37   */
38  public class SampledClockModel implements ClockModel {
39  
40      /** sample. */
41      private final ImmutableTimeStampedCache<ClockOffset> sample;
42  
43      /** Simple constructor.
44       * @param sample                clock offsets sample
45       * @param nbInterpolationPoints number of points to use in interpolation
46       */
47      public SampledClockModel(final List<ClockOffset> sample, final int nbInterpolationPoints) {
48          this.sample = new ImmutableTimeStampedCache<>(nbInterpolationPoints, sample);
49      }
50  
51      /** Get the clock offsets cache.
52       * @return clock offsets cache
53       */
54      public ImmutableTimeStampedCache<ClockOffset> getCache() {
55          return sample;
56      }
57  
58      /** {@inheritDoc} */
59      @Override
60      public AbsoluteDate getValidityStart() {
61          return sample.getEarliest().getDate();
62      }
63  
64      /** {@inheritDoc} */
65      @Override
66      public AbsoluteDate getValidityEnd() {
67          return sample.getLatest().getDate();
68      }
69  
70      /** {@inheritDoc} */
71      @Override
72      public ClockOffset getOffset(final AbsoluteDate date) {
73          return new ClockOffsetHermiteInterpolator(sample.getMaxNeighborsSize()).
74              interpolate(date, sample.getNeighbors(date));
75      }
76  
77      /** {@inheritDoc} */
78      @Override
79      public <T extends CalculusFieldElement<T>> FieldClockOffset<T> getFieldOffset(final FieldAbsoluteDate<T> date) {
80  
81          // convert the neighbors to field
82          final Field<T> field = date.getField();
83          final T zero = field.getZero();
84          final Stream<FieldClockOffset<T>> fieldSample =
85              sample.
86                  getNeighbors(date.toAbsoluteDate()).
87                  map(c -> {
88                      final FieldAbsoluteDate<T> dateF = new FieldAbsoluteDate<>(field, c.getDate());
89                      final T                    biasF = zero.newInstance(c.getBias());
90                      final T rateF;
91                      final T accelerationF;
92                      if (Double.isNaN(c.getRate())) {
93                          // no rate available
94                          rateF         = null;
95                          accelerationF = null;
96                      } else {
97                          // rate available
98                          rateF = zero.newInstance(c.getRate());
99                          accelerationF = Double.isNaN(c.getAcceleration()) ?
100                                         null :
101                                         zero.newInstance(c.getAcceleration());
102                     }
103                     return new FieldClockOffset<>(dateF, biasF, rateF, accelerationF);
104                 });
105 
106         // perform interpolation
107         final FieldClockOffsetHermiteInterpolator<T> interpolator =
108             new FieldClockOffsetHermiteInterpolator<>(sample.getMaxNeighborsSize());
109         return interpolator.interpolate(date, fieldSample);
110 
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public List<ParameterDriver> getParametersDrivers() {
116         throw new OrekitException(OrekitMessages.INTERNAL_ERROR);
117     }
118 
119 
120     /** {@inheritDoc} */
121     @Override
122     public FieldClockModel<Gradient> getFieldModel(final int freeParameters,
123             final Map<String, Integer> indices, final AbsoluteDate date) {
124         throw new OrekitException(OrekitMessages.INTERNAL_ERROR);
125     }
126 
127 }