1 /* Copyright 2022-2025 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.propagation.analytical.gnss.data;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.analysis.differentiation.FieldGradient;
22 import org.hipparchus.analysis.differentiation.FieldGradientField;
23 import org.hipparchus.analysis.differentiation.Gradient;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.MathArrays;
26 import org.orekit.time.TimeInterval;
27 import org.orekit.utils.Constants;
28 import org.orekit.utils.drivers.ParameterDriver;
29
30 import java.util.Arrays;
31 import java.util.List;
32
33 /** Factory for non-Keplerian drivers.
34 * @since 14.0
35 */
36 public class NonKeplerianDriversFactory {
37
38 /** Name for time parameter. */
39 public static final String TIME = "GnssTime";
40
41 /** Name for change rate in semi-major axis parameter. */
42 public static final String A_DOT = "GnssADot";
43
44 /** Name for delta of satellite mean motion. */
45 public static final String DELTA_N0 = "GnssDeltaN0";
46
47 /** Name for change rate in Δn₀. */
48 public static final String DELTA_N0_DOT = "GnssDeltaN0Dot";
49
50 /** Name for inclination rate parameter. */
51 public static final String INCLINATION_RATE = "GnssInclinationRate";
52
53 /** Name for longitude rate parameter. */
54 public static final String LONGITUDE_RATE = "GnssLongitudeRate";
55
56 /** Name for cosine of latitude argument harmonic parameter. */
57 public static final String LATITUDE_COSINE = "GnssLatitudeCosine";
58
59 /** Name for sine of latitude argument harmonic parameter. */
60 public static final String LATITUDE_SINE = "GnssLatitudeSine";
61
62 /** Name for cosine of orbit radius harmonic parameter. */
63 public static final String RADIUS_COSINE = "GnssRadiusCosine";
64
65 /** Name for sine of orbit radius harmonic parameter. */
66 public static final String RADIUS_SINE = "GnssRadiusSine";
67
68 /** Name for cosine of inclination harmonic parameter. */
69 public static final String INCLINATION_COSINE = "GnssInclinationCosine";
70
71 /** Name for sine of inclination harmonic parameter. */
72 public static final String INCLINATION_SINE = "GnssInclinationSine";
73
74 /** Name for zero-th order clock correction parameter. */
75 public static final String AF0 = "GnssClock0";
76
77 /** Name for first order clock correction parameter. */
78 public static final String AF1 = "GnssClock1";
79
80 /** Name for second order clock correction parameter. */
81 public static final String AF2 = "GnssClock2";
82
83 /** Index of time in the list returned by {@link #getParametersDrivers()}. */
84 public static final int TIME_INDEX = 0;
85
86 /** Index of change rate in semi-major axis parameter in the list returned by {@link #getParametersDrivers()}. */
87 public static final int A_DOT_INDEX = TIME_INDEX + 1;
88
89 /** Index of delta of satellite mean motion in the list returned by {@link #getParametersDrivers()}. */
90 public static final int DELTA_N0_INDEX = A_DOT_INDEX + 1;
91
92 /** Index of change rate in Δn₀ in the list returned by {@link #getParametersDrivers()}. */
93 public static final int DELTA_N0_DOT_INDEX = DELTA_N0_INDEX + 1;
94
95 /** Index of inclination rate in the list returned by {@link #getParametersDrivers()}. */
96 public static final int I_DOT_INDEX = DELTA_N0_DOT_INDEX + 1;
97
98 /** Index of longitude rate in the list returned by {@link #getParametersDrivers()}. */
99 public static final int OMEGA_DOT_INDEX = I_DOT_INDEX + 1;
100
101 /** Index of cosine on latitude argument in the list returned by {@link #getParametersDrivers()}. */
102 public static final int CUC_INDEX = OMEGA_DOT_INDEX + 1;
103
104 /** Index of sine on latitude argument in the list returned by {@link #getParametersDrivers()}. */
105 public static final int CUS_INDEX = CUC_INDEX + 1;
106
107 /** Index of cosine on radius in the list returned by {@link #getParametersDrivers()}. */
108 public static final int CRC_INDEX = CUS_INDEX + 1;
109
110 /** Index of sine on radius in the list returned by {@link #getParametersDrivers()}. */
111 public static final int CRS_INDEX = CRC_INDEX + 1;
112
113 /** Index of cosine on inclination in the list returned by {@link #getParametersDrivers()}. */
114 public static final int CIC_INDEX = CRS_INDEX + 1;
115
116 /** Index of sine on inclination in the list returned by {@link #getParametersDrivers()}. */
117 public static final int CIS_INDEX = CIC_INDEX + 1;
118
119 /** Index of zero-th order clock correction in the list returned by {@link #getParametersDrivers()}. */
120 public static final int AF0_INDEX = CIS_INDEX + 1;
121
122 /** Index of first order clock correction in the list returned by {@link #getParametersDrivers()}. */
123 public static final int AF1_INDEX = AF0_INDEX + 1;
124
125 /** Index of second order clock correction in the list returned by {@link #getParametersDrivers()}. */
126 public static final int AF2_INDEX = AF1_INDEX + 1;
127
128 /** Size of parameters array. */
129 public static final int SIZE = AF2_INDEX + 1;
130
131 /** Reference time. */
132 private final ParameterDriver timeDriver;
133
134 /** Change rate in semi-major axis (m/s). */
135 private final ParameterDriver aDotDriver;
136
137 /** Delta of satellite mean motion. */
138 private final ParameterDriver deltaN0Driver;
139
140 /** Change rate in Δn₀. */
141 private final ParameterDriver deltaN0DotDriver;
142
143 /** Inclination rate (rad/s). */
144 private final ParameterDriver iDotDriver;
145
146 /** Rate of right ascension (rad/s). */
147 private final ParameterDriver domDriver;
148
149 /** Amplitude of the cosine harmonic correction term to the argument of latitude. */
150 private final ParameterDriver cucDriver;
151
152 /** Amplitude of the sine harmonic correction term to the argument of latitude. */
153 private final ParameterDriver cusDriver;
154
155 /** Amplitude of the cosine harmonic correction term to the orbit radius. */
156 private final ParameterDriver crcDriver;
157
158 /** Amplitude of the sine harmonic correction term to the orbit radius. */
159 private final ParameterDriver crsDriver;
160
161 /** Amplitude of the cosine harmonic correction term to the inclination. */
162 private final ParameterDriver cicDriver;
163
164 /** Amplitude of the sine harmonic correction term to the inclination. */
165 private final ParameterDriver cisDriver;
166
167 /** SV zero-th order clock correction (s). */
168 private final ParameterDriver af0Driver;
169
170 /** SV first order clock correction (s/s). */
171 private final ParameterDriver af1Driver;
172
173 /** SV second order clock correction (s/s²). */
174 private final ParameterDriver af2Driver;
175
176 /** Simple constructor.
177 */
178 public NonKeplerianDriversFactory() {
179
180 // propagation drivers
181 this.timeDriver = new ParameterDriver(TIME, 0.0, FastMath.scalb(1.0, -10),
182 0, 7 * Constants.JULIAN_DAY, TimeInterval.UNLIMITED);
183 this.aDotDriver = new ParameterDriver(A_DOT, 0.0, FastMath.scalb(1.0, -10),
184 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
185 TimeInterval.UNLIMITED);
186 this.deltaN0Driver = new ParameterDriver(DELTA_N0, 0.0, FastMath.scalb(1.0, -36),
187 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
188 TimeInterval.UNLIMITED);
189 this.deltaN0DotDriver = new ParameterDriver(DELTA_N0_DOT, 0.0, FastMath.scalb(1.0, -46),
190 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
191 TimeInterval.UNLIMITED);
192 this.iDotDriver = new ParameterDriver(INCLINATION_RATE, 0.0, FastMath.scalb(1.0, -34),
193 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
194 TimeInterval.UNLIMITED);
195 this.domDriver = new ParameterDriver(LONGITUDE_RATE, 0.0, FastMath.scalb(1.0, -34),
196 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
197 TimeInterval.UNLIMITED);
198 this.cucDriver = new ParameterDriver(LATITUDE_COSINE, 0.0, FastMath.scalb(1.0, -24),
199 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
200 TimeInterval.UNLIMITED);
201 this.cusDriver = new ParameterDriver(LATITUDE_SINE, 0.0, FastMath.scalb(1.0, -24),
202 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
203 TimeInterval.UNLIMITED);
204 this.crcDriver = new ParameterDriver(RADIUS_COSINE, 0.0, FastMath.scalb(1.0, 0),
205 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
206 TimeInterval.UNLIMITED);
207 this.crsDriver = new ParameterDriver(RADIUS_SINE, 0.0, FastMath.scalb(1.0, 0),
208 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
209 TimeInterval.UNLIMITED);
210 this.cicDriver = new ParameterDriver(INCLINATION_COSINE, 0.0, FastMath.scalb(1.0, -24),
211 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
212 TimeInterval.UNLIMITED);
213 this.cisDriver = new ParameterDriver(INCLINATION_SINE, 0.0, FastMath.scalb(1.0, -24),
214 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
215 TimeInterval.UNLIMITED);
216
217 // clock drivers
218 this.af0Driver = new ParameterDriver(AF0, 0.0, FastMath.scalb(1.0, -26),
219 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TimeInterval.UNLIMITED);
220 this.af1Driver = new ParameterDriver(AF1, 0.0, FastMath.scalb(1.0, -42),
221 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TimeInterval.UNLIMITED);
222 this.af2Driver = new ParameterDriver(AF2, 0.0, FastMath.scalb(1.0, -58),
223 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, TimeInterval.UNLIMITED);
224
225 }
226
227 /** Reset the parameters drivers from existing elements.
228 * @param elements elements to use for reset
229 */
230 public void reset(final GNSSOrbitalElements<?> elements) {
231 reset(timeDriver, elements.getTimeOfEphemeris().getSecondsInWeek());
232 reset(aDotDriver, elements.getADot());
233 reset(deltaN0Driver, elements.getDeltaN0());
234 reset(deltaN0DotDriver, elements.getDeltaN0Dot());
235 reset(iDotDriver, elements.getIDot());
236 reset(domDriver, elements.getOmegaDot());
237 reset(cucDriver, elements.getCuc());
238 reset(cusDriver, elements.getCus());
239 reset(crcDriver, elements.getCrc());
240 reset(crsDriver, elements.getCrs());
241 reset(cicDriver, elements.getCic());
242 reset(cisDriver, elements.getCis());
243 reset(af0Driver, elements.getAf0());
244 reset(af1Driver, elements.getAf1());
245 reset(af2Driver, elements.getAf2());
246 }
247
248 /** Reset the parameters drivers from existing elements.
249 * @param elements elements to use for reset
250 */
251 public void reset(final FieldGnssOrbitalElements<?, ?> elements) {
252 reset(timeDriver, elements.getTimeOfEphemeris().getGnssDate().getSecondsInWeek());
253 reset(aDotDriver, elements.getADot().getReal());
254 reset(deltaN0Driver, elements.getDeltaN0().getReal());
255 reset(deltaN0DotDriver, elements.getDeltaN0Dot().getReal());
256 reset(iDotDriver, elements.getIDot().getReal());
257 reset(domDriver, elements.getOmegaDot().getReal());
258 reset(cucDriver, elements.getCuc().getReal());
259 reset(cusDriver, elements.getCus().getReal());
260 reset(crcDriver, elements.getCrc().getReal());
261 reset(crsDriver, elements.getCrs().getReal());
262 reset(cicDriver, elements.getCic().getReal());
263 reset(cisDriver, elements.getCis().getReal());
264 reset(af0Driver, elements.getAf0().getReal());
265 reset(af1Driver, elements.getAf1().getReal());
266 reset(af2Driver, elements.getAf2().getReal());
267 }
268
269 /** Reset one driver.
270 * @param driver driver to reset
271 * @param value new value (also used as reference)
272 */
273 private void reset (final ParameterDriver driver, final double value) {
274 driver.setValue(value);
275 driver.setReferenceValue(value);
276 }
277
278 /** Get the 15 drivers for the non-Keplerian parameters.
279 * <p>
280 * Only the 15 non-Keplerian parameters (12 evolution parameters and 3 clock parameters)
281 * are listed here:
282 * Time driver at index {@link #TIME_INDEX},
283 * ADot driver at index {@link #A_DOT_INDEX},
284 * DeltaN0 driver at index {@link #DELTA_N0_INDEX},
285 * DeltaN0Dot driver at index {@link #DELTA_N0_DOT_INDEX},
286 * IDot driver at index {@link #I_DOT_INDEX},
287 * OmegaDot driver at index {@link #OMEGA_DOT_INDEX},
288 * Cuc driver at index {@link #CUC_INDEX},
289 * Cus driver at index {@link #CUS_INDEX},
290 * Crc driver at index {@link #CRC_INDEX},
291 * Crs driver at index {@link #CRS_INDEX},
292 * Cic driver at index {@link #CIC_INDEX},
293 * Cis driver at index {@link #CIS_INDEX},
294 * af0 driver at index {@link #AF0_INDEX},
295 * af1 driver at index {@link #AF1_INDEX},
296 * and af2 driver at index {@link #AF2_INDEX}.
297 * </p>
298 * @return 15 drivers for the non-Keplerian parameters
299 */
300 public List<ParameterDriver> getParametersDrivers() {
301
302 // ensure the parameters are really at the advertised indices
303 final ParameterDriver[] array = new ParameterDriver[SIZE];
304
305 array[TIME_INDEX] = timeDriver;
306 array[A_DOT_INDEX] = aDotDriver;
307 array[DELTA_N0_INDEX] = deltaN0Driver;
308 array[DELTA_N0_DOT_INDEX] = deltaN0DotDriver;
309 array[I_DOT_INDEX] = iDotDriver;
310 array[OMEGA_DOT_INDEX] = domDriver;
311 array[CUC_INDEX] = cucDriver;
312 array[CUS_INDEX] = cusDriver;
313 array[CRC_INDEX] = crcDriver;
314 array[CRS_INDEX] = crsDriver;
315 array[CIC_INDEX] = cicDriver;
316 array[CIS_INDEX] = cisDriver;
317
318 array[AF0_INDEX] = af0Driver;
319 array[AF1_INDEX] = af1Driver;
320 array[AF2_INDEX] = af2Driver;
321
322 return Arrays.asList(array);
323
324 }
325
326 /** Get driver for reference time of the GNSS orbit as a duration from week start.
327 * @return driver for reference time of the GNSS orbit (s)
328 */
329 public ParameterDriver getTimeDriver() {
330 return timeDriver;
331 }
332
333 /** Get driver for change rate in semi-major axis.
334 * @return driver for the change rate in semi-major axis
335 */
336 public ParameterDriver getADotDriver() {
337 return aDotDriver;
338 }
339
340 /** Get driver for the delta of satellite mean motion.
341 * @return driver for the delta of satellite mean motion
342 */
343 public ParameterDriver getDeltaN0Driver() {
344 return deltaN0Driver;
345 }
346
347 /** Get driver for the change rate in Δn₀.
348 * @return driver for change rate in Δn₀
349 */
350 public ParameterDriver getDeltaN0DotDriver() {
351 return deltaN0DotDriver;
352 }
353
354 /** Get driver for rate of inclination angle.
355 * @return driver for rate of inclination angle (rad/s)
356 */
357 public ParameterDriver getIDotDriver() {
358 return iDotDriver;
359 }
360
361 /** Get driver for rate of right ascension.
362 * @return driver for rate of right ascension (rad/s)
363 */
364 public ParameterDriver getOmegaDotDriver() {
365 return domDriver;
366 }
367
368 /** Get driver for amplitude of the cosine harmonic correction term to the argument of latitude.
369 * @return driver for amplitude of the cosine harmonic correction term to the argument of latitude (rad)
370 */
371 public ParameterDriver getCucDriver() {
372 return cucDriver;
373 }
374
375 /** Get driver for amplitude of the sine harmonic correction term to the argument of latitude.
376 * @return driver for amplitude of the sine harmonic correction term to the argument of latitude (rad)
377 */
378 public ParameterDriver getCusDriver() {
379 return cusDriver;
380 }
381
382 /** Get driver for amplitude of the cosine harmonic correction term to the orbit radius.
383 * @return driver for amplitude of the cosine harmonic correction term to the orbit radius (m)
384 */
385 public ParameterDriver getCrcDriver() {
386 return crcDriver;
387 }
388
389 /** Get driver for amplitude of the sine harmonic correction term to the orbit radius.
390 * @return driver for amplitude of the sine harmonic correction term to the orbit radius (m)
391 */
392 public ParameterDriver getCrsDriver() {
393 return crsDriver;
394 }
395
396 /** Get driver for amplitude of the cosine harmonic correction term to the angle of inclination.
397 * @return driver for amplitude of the cosine harmonic correction term to the angle of inclination (rad)
398 */
399 public ParameterDriver getCicDriver() {
400 return cicDriver;
401 }
402
403 /** Get driver for amplitude of the sine harmonic correction term to the angle of inclination.
404 * @return driver for amplitude of the sine harmonic correction term to the angle of inclination (rad)
405 */
406 public ParameterDriver getCisDriver() {
407 return cisDriver;
408 }
409
410 /** Get driver for SV zero-th order clock correction.
411 * @return driver for SV zero-th order clock correction (s)
412 */
413 public ParameterDriver getAf0Driver() {
414 return af0Driver;
415 }
416
417 /** Get driver for SV first order clock correction.
418 * @return driver for SV first order clock correction (s/s)
419 */
420 public ParameterDriver getAf1Driver() {
421 return af1Driver;
422 }
423
424 /** Get driver for SV second order clock correction.
425 * @return driver for SV second order clock correction (s/s²)
426 */
427 public ParameterDriver getAf2Driver() {
428 return af2Driver;
429 }
430
431 /** Get the non-Keplerian elements as gradient variables or constants, depending on selection status.
432 * @param freeParameters total number of free parameters in the gradient
433 * @return non-Keplerian elements as gradient variables or constants
434 */
435 public Gradient[] toGradients(final int freeParameters) {
436 final Filler filler = new Filler(freeParameters);
437 filler.manage(timeDriver, TIME_INDEX);
438 filler.manage(aDotDriver, A_DOT_INDEX);
439 filler.manage(deltaN0Driver, DELTA_N0_INDEX);
440 filler.manage(deltaN0DotDriver, DELTA_N0_DOT_INDEX);
441 filler.manage(iDotDriver, I_DOT_INDEX);
442 filler.manage(domDriver, OMEGA_DOT_INDEX);
443 filler.manage(cucDriver, CUC_INDEX);
444 filler.manage(cusDriver, CUS_INDEX);
445 filler.manage(crcDriver, CRC_INDEX);
446 filler.manage(crsDriver, CRS_INDEX);
447 filler.manage(cicDriver, CIC_INDEX);
448 filler.manage(cisDriver, CIS_INDEX);
449 filler.manage(af0Driver, AF0_INDEX);
450 filler.manage(af1Driver, AF1_INDEX);
451 filler.manage(af2Driver, AF2_INDEX);
452 return filler.gradients;
453 }
454
455 /** Get the non-Keplerian elements as gradient variables or constants, depending on selection status.
456 * @param <T> type of the field elements
457 * @param field field
458 * @param freeParameters total number of free parameters in the gradient
459 * @return non-Keplerian elements as gradient variables or constants
460 */
461 public <T extends CalculusFieldElement<T>> FieldGradient<T>[] toGradients(final Field<T> field,
462 final int freeParameters) {
463 final FieldFiller<T> filler = new FieldFiller<>(field, freeParameters);
464 filler.manage(timeDriver, TIME_INDEX);
465 filler.manage(aDotDriver, A_DOT_INDEX);
466 filler.manage(deltaN0Driver, DELTA_N0_INDEX);
467 filler.manage(deltaN0DotDriver, DELTA_N0_DOT_INDEX);
468 filler.manage(iDotDriver, I_DOT_INDEX);
469 filler.manage(domDriver, OMEGA_DOT_INDEX);
470 filler.manage(cucDriver, CUC_INDEX);
471 filler.manage(cusDriver, CUS_INDEX);
472 filler.manage(crcDriver, CRC_INDEX);
473 filler.manage(crsDriver, CRS_INDEX);
474 filler.manage(cicDriver, CIC_INDEX);
475 filler.manage(cisDriver, CIS_INDEX);
476 filler.manage(af0Driver, AF0_INDEX);
477 filler.manage(af1Driver, AF1_INDEX);
478 filler.manage(af2Driver, AF2_INDEX);
479 return filler.gradients;
480 }
481
482 /** Array filler for gradients.
483 * @since 14.0
484 */
485 private static class Filler {
486
487 /** Total number of free parameters in the gradient. */
488 private final int freeParameters;
489
490 /** Gradient array. */
491 private final Gradient[] gradients;
492
493 /** Partial derivative index. */
494 private int derivative;
495
496 /** Simple constructor.
497 * @param freeParameters total number of free parameters in the gradient
498 */
499 Filler(final int freeParameters) {
500 this.freeParameters = freeParameters;
501 this.gradients = new Gradient[SIZE];
502 this.derivative = 6;
503 }
504
505 /** Manage one driver.
506 * @param driver driver to manage
507 * @param index index of the driver in the array
508 */
509 private void manage(final ParameterDriver driver, final int index) {
510 if (driver.isSelected()) {
511 // this driver should be managed as a variable
512 gradients[index] = Gradient.variable(freeParameters, derivative, driver.getValue());
513 ++derivative;
514 } else {
515 // this driver should be managed as a constant
516 gradients[index] = Gradient.constant(freeParameters, driver.getValue());
517 }
518 }
519
520 }
521
522 /** Array filler for gradients.
523 * @param <T> field to which elements belong
524 * @since 14.0
525 */
526 private static class FieldFiller<T extends CalculusFieldElement<T>> {
527
528 /** Field. */
529 private final Field<T> field;
530
531 /** Total number of free parameters in the gradient. */
532 private final int freeParameters;
533
534 /** Gradient array. */
535 private final FieldGradient<T>[] gradients;
536
537 /** Partial derivative index. */
538 private int derivative;
539
540 /** Simple constructor.
541 * @param field field
542 * @param freeParameters total number of free parameters in the gradient
543 */
544 FieldFiller(final Field<T> field, final int freeParameters) {
545 this.field = field;
546 this.freeParameters = freeParameters;
547 this.gradients = MathArrays.buildArray(FieldGradientField.getField(field, freeParameters), SIZE);
548 this.derivative = 6;
549 }
550
551 /** Manage one driver.
552 * @param driver driver to manage
553 * @param index index of the driver in the array
554 */
555 private void manage(final ParameterDriver driver, final int index) {
556 if (driver.isSelected()) {
557 // this driver should be managed as a variable
558 gradients[index] = FieldGradient.variable(freeParameters, derivative,
559 field.getZero().newInstance(driver.getValue()));
560 ++derivative;
561 } else {
562 // this driver should be managed as a constant
563 gradients[index] = FieldGradient.constant(freeParameters,
564 field.getZero().newInstance(driver.getValue()));
565 }
566 }
567
568 }
569
570 }