1   /* Copyright 2002-2026 CS GROUP
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.utils.drivers;
18  
19  import org.hipparchus.exception.LocalizedCoreFormats;
20  import org.hipparchus.util.FastMath;
21  import org.hipparchus.util.Precision;
22  import org.orekit.errors.OrekitException;
23  import org.orekit.errors.OrekitMessages;
24  import org.orekit.time.TimeInterval;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.Iterator;
29  import java.util.List;
30  
31  /** Common features for both {@link ParameterDriver} and {@link FieldParameterDriver}.
32   * @param <P> type of the parameter driver
33   * @param <O> type of the parameter observer
34   * @see ParameterDriver
35   * @see FieldParameterDriver
36   * @author Luc Maisonobe
37   * @since 14.0
38   */
39  public abstract class BaseParameterDriver<P extends BaseParameterDriver<P, O>,
40                                            O extends BaseParameterObserver<P, O>> {
41  
42      /** Name of the parameter. */
43      private String name;
44  
45      /** Scaling factor. */
46      private double scale;
47  
48      /** Minimum value. */
49      private double minValue;
50  
51      /** Maximum value. */
52      private double maxValue;
53  
54      /** Validity interval.
55       * @since 14.0
56       */
57      private TimeInterval validity;
58  
59      /** Selection status.
60       * <p>
61       * Selection is used for estimated parameters in orbit determination,
62       * or to compute the Jacobian matrix in partial derivatives computation.
63       * </p>
64       */
65      private boolean selected;
66  
67      /** Observers observing this driver. */
68      private final List<O> observers;
69  
70      /**
71       * Simple constructor.
72       * <p>
73       * At construction, the parameter is configured as <em>not</em> selected, the reference date is set to {@code null},
74       * the value is set to the {@code referenceValue}.
75       * </p>
76       * @param name           name of the parameter
77       * @param scale          scaling factor to convert the parameters value to non-dimensional (typically set to the
78       *                       expected standard deviation of the parameter), it must be non-zero
79       * @param minValue       minimum value allowed
80       * @param maxValue       maximum value allowed
81       * @param validity       validity interval
82       */
83      public BaseParameterDriver(final String name, final double scale,
84                                 final double minValue, final double maxValue,
85                                 final TimeInterval validity) {
86  
87          if (FastMath.abs(scale) <= Precision.SAFE_MIN) {
88              throw new OrekitException(OrekitMessages.TOO_SMALL_SCALE_FOR_PARAMETER, name, scale);
89          }
90  
91          this.name      = name;
92          this.scale     = scale;
93          this.minValue  = minValue;
94          this.maxValue  = maxValue;
95          this.validity  = validity;
96          this.selected  = false;
97          this.observers = new ArrayList<>();
98      }
99  
100     /** Add an observer for this driver.
101      * @param observer observer to add
102      */
103     public void addObserver(final O observer) {
104         observers.add(observer);
105     }
106 
107     /** Remove an observer.
108      * @param observer observer to remove
109      * @since 9.1
110      */
111     public void removeObserver(final O observer) {
112         for (final Iterator<O> iterator = observers.iterator(); iterator.hasNext();) {
113             if (iterator.next() == observer) {
114                 iterator.remove();
115                 return;
116             }
117         }
118     }
119 
120     /** Replace an observer.
121      * @param oldObserver observer to replace
122      * @param newObserver new observer to use
123      * @since 10.1
124      */
125     public void replaceObserver(final O oldObserver, final O newObserver) {
126         for (int i = 0; i < observers.size(); ++i) {
127             if (observers.get(i) == oldObserver) {
128                 observers.set(i, newObserver);
129             }
130         }
131     }
132 
133     /** Get the observers for this driver.
134      * @return an unmodifiable view of the observers for this driver
135      * @since 9.1
136      */
137     public List<O> getObservers() {
138         return Collections.unmodifiableList(observers);
139     }
140 
141     /** Get parameter driver general name.
142      * @return name
143      */
144     public String getName() {
145         return name;
146     }
147 
148     /** Change the general name of this parameter driver.
149      * @param name new name
150      */
151     public void setName(final String name) {
152         final String previousName = this.name;
153         this.name = name;
154         @SuppressWarnings("unchecked")
155         final P self = (P) this;
156         for (final O observer : observers) {
157             observer.nameChanged(previousName, self);
158         }
159     }
160 
161     /** Get minimum parameter value.
162      * @return minimum parameter value
163      */
164     public double getMinValue() {
165         return minValue;
166     }
167 
168     /** Set minimum parameter value.
169      * @since 9.3
170      * @param minValue the minimum value to set.
171      */
172     public void setMinValue(final double minValue) {
173 
174         // safety check
175         if (minValue > maxValue) {
176             throw new OrekitException(LocalizedCoreFormats.NUMBER_TOO_LARGE, minValue, maxValue);
177         }
178 
179         final double previousMinValue = this.minValue;
180         this.minValue = minValue;
181         @SuppressWarnings("unchecked")
182         final P self = (P) this;
183         for (final O observer : observers) {
184             observer.minValueChanged(previousMinValue, self);
185         }
186 
187     }
188 
189     /** Get maximum parameter value.
190      * @return maximum parameter value
191      */
192     public double getMaxValue() {
193         return maxValue;
194     }
195 
196     /** Set maximum parameter value.
197      * @param maxValue the maximum value to set.
198      */
199     public void setMaxValue(final double maxValue) {
200 
201         // safety check
202         if (maxValue < minValue) {
203             throw new OrekitException(LocalizedCoreFormats.NUMBER_TOO_SMALL, maxValue, minValue);
204         }
205 
206         final double previousMaxValue = this.maxValue;
207         this.maxValue = maxValue;
208         @SuppressWarnings("unchecked")
209         final P self = (P) this;
210         for (final O observer : observers) {
211             observer.maxValueChanged(previousMaxValue, self);
212         }
213 
214     }
215 
216     /** Get scale.
217      * @return scale
218      */
219     public double getScale() {
220         return scale;
221     }
222 
223     /** Set scale.
224      * @since 9.3
225      * @param scale the scale to set.
226      */
227     public void setScale(final double scale) {
228         final double previousScale = this.scale;
229         this.scale = scale;
230         @SuppressWarnings("unchecked")
231         final P self = (P) this;
232         for (final O observer : observers) {
233             observer.scaleChanged(previousScale, self);
234         }
235     }
236 
237     /** Get the validity interval.
238      * @return validity interval
239      * @since 14.0
240      */
241     public TimeInterval getValidity() {
242         return validity;
243     }
244 
245     /** Set the validity interval.
246      * @param validity validity interval
247      * @since 14.0
248      */
249     public void setValidity(final TimeInterval validity) {
250         final TimeInterval previousValidity = getValidity();
251         this.validity = validity;
252         @SuppressWarnings("unchecked")
253         final P self = (P) this;
254         for (final O observer : observers) {
255             observer.validityChanged(previousValidity, self);
256         }
257     }
258 
259     /** Configure a parameter selection status.
260      * <p>
261      * Selection is used for estimated parameters in orbit determination,
262      * or to compute the Jacobian matrix in partial derivatives computation.
263      * </p>
264      * @param selected if true the parameter is selected,
265      * otherwise it will be fixed
266      */
267     public void setSelected(final boolean selected) {
268         final boolean previousSelection = isSelected();
269         this.selected = selected;
270         @SuppressWarnings("unchecked")
271         final P self = (P) this;
272         for (final O observer : observers) {
273             observer.selectionChanged(previousSelection, self);
274         }
275     }
276 
277     /** Check if parameter is selected.
278      * <p>
279      * Selection is used for estimated parameters in orbit determination,
280      * or to compute the Jacobian matrix in partial derivatives computation.
281      * </p>
282      * @return true if parameter is selected, false if it is not
283      */
284     public boolean isSelected() {
285         return selected;
286     }
287 
288 }