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 org.hipparchus.CalculusFieldElement;
20  import org.orekit.errors.OrekitException;
21  import org.orekit.errors.OrekitMessages;
22  import org.orekit.time.AbsoluteDate;
23  import org.orekit.time.FieldAbsoluteDate;
24  import org.orekit.utils.TimeSpanMap;
25  
26  /**
27   * Offset clock model aggregating several other clock models.
28   *
29   * @param <T> type of the field elements
30   * @author Luc Maisonobe
31   * @since 14.0
32   */
33  public class AggregatedFieldClockModel<T extends CalculusFieldElement<T>>
34      implements FieldClockModel<T> {
35  
36      /** Underlying clock models. */
37      private final TimeSpanMap<FieldClockModel<T>> models;
38  
39      /** Non-field version of the model. */
40      private final AggregatedClockModel nonField;
41  
42      /** Simple constructor.
43       * @param models underlying clock models
44       */
45      public AggregatedFieldClockModel(final TimeSpanMap<FieldClockModel<T>> models) {
46  
47          try {
48              // we ignore the result, we just want to check some data is present
49              models.getFirstNonNullSpan();
50          } catch (OrekitException oe) {
51              throw new OrekitException(oe, OrekitMessages.NOT_ENOUGH_DATA, 0);
52          }
53  
54          this.models = models;
55  
56          // create non-field version
57          final TimeSpanMap<ClockModel> nonFieldMap = new TimeSpanMap<>(null);
58          for (TimeSpanMap.Span<FieldClockModel<T>> span = models.getFirstSpan(); span != null; span = span.next()) {
59              nonFieldMap.addValidBetween(span.getData() == null ? null : span.getData().toNonField(),
60                                          span.getStart(), span.getEnd());
61          }
62          this.nonField = new AggregatedClockModel(nonFieldMap);
63  
64      }
65  
66      /** Get the underlying models.
67       * @return underlying models
68       */
69      public TimeSpanMap<FieldClockModel<T>> getModels() {
70          return models;
71      }
72  
73      /** {@inheritDoc} */
74      @Override
75      public AbsoluteDate getValidityStart() {
76          return models.getFirstNonNullSpan().getStart();
77      }
78  
79      /** {@inheritDoc} */
80      @Override
81      public AbsoluteDate getValidityEnd() {
82          return models.getLastNonNullSpan().getEnd();
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      public FieldClockOffset<T> getOffset(final FieldAbsoluteDate<T> date) {
88          return getModel(date).getOffset(date);
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public AggregatedClockModel toNonField() {
94          return nonField;
95      }
96  
97      /**
98       * Get the model valid at specified date.
99       *
100      * @param date date for which model is requested
101      * @return clock model valid at date
102      */
103     private FieldClockModel<T> getModel(final FieldAbsoluteDate<T> date) {
104         final FieldClockModel<T> clockModel = models.get(date.toAbsoluteDate());
105         if (clockModel == null) {
106             // this may happen if map is limited or not contiguous
107             // typically for models retrieved from SP3Ephemeris
108             throw new OrekitException(OrekitMessages.NO_DATA_GENERATED, date);
109         }
110         return clockModel;
111     }
112 
113 }