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 }