1   /* Copyright 2002-2025 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.propagation;
18  
19  import org.hipparchus.analysis.interpolation.HermiteInterpolator;
20  import org.hipparchus.linear.BlockRealMatrix;
21  import org.hipparchus.linear.MatrixUtils;
22  import org.hipparchus.linear.RealMatrix;
23  import org.orekit.errors.OrekitInternalError;
24  import org.orekit.frames.Frame;
25  import org.orekit.frames.LOFType;
26  import org.orekit.orbits.Orbit;
27  import org.orekit.orbits.OrbitType;
28  import org.orekit.orbits.PositionAngleType;
29  import org.orekit.time.AbsoluteDate;
30  import org.orekit.time.TimeInterpolator;
31  import org.orekit.time.TimeStampedPair;
32  import org.orekit.utils.CartesianDerivativesFilter;
33  
34  import java.util.ArrayList;
35  import java.util.List;
36  
37  /**
38   * State covariance Keplerian quintic interpolator.
39   * <p>
40   * Its purpose is to interpolate state covariance between tabulated state covariances using polynomial interpolation. To do
41   * so, it uses a {@link HermiteInterpolator} and compute the first and second order derivatives at tabulated states assuming
42   * a standard Keplerian motion depending on given derivatives filter.
43   * <p>
44   * It gives very accurate results as explained <a
45   * href="https://orekit.org/doc/technical-notes/Implementation_of_covariance_interpolation_in_Orekit.pdf">here</a>. In the
46   * very poorly tracked test case evolving in a highly dynamical environment mentioned in the linked thread, the user can
47   * expect at worst errors of less than 0.2% in position sigmas and less than 0.35% in velocity sigmas with steps of 40mn
48   * between tabulated values.
49   * <p>
50   * However, note that this method does not guarantee the positive definiteness of the computed state covariance as opposed to
51   * {@link StateCovarianceBlender}.
52   *
53   * @author Vincent Cucchietti
54   * @see HermiteInterpolator
55   * @see StateCovarianceBlender
56   */
57  public class StateCovarianceKeplerianHermiteInterpolator extends AbstractStateCovarianceInterpolator {
58  
59      /**
60       * Filter defining if only the state covariance value are used or if first or/and second Keplerian derivatives should be
61       * used.
62       */
63      private final CartesianDerivativesFilter filter;
64  
65      /**
66       * Constructor using an output local orbital frame and :
67       * <ul>
68       *     <li>Default number of interpolation points of {@code DEFAULT_INTERPOLATION_POINTS}</li>
69       *     <li>Default extrapolation threshold value ({@code DEFAULT_EXTRAPOLATION_THRESHOLD_SEC} s)</li>
70       *     <li>Use of position and two time derivatives during interpolation</li>
71       * </ul>
72       * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
73       * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
74       * phenomenon</a> and numerical problems (including NaN appearing).
75       * <p>
76       * <b>BEWARE:</b> If the output local orbital frame is not considered pseudo-inertial, all the covariance components
77       * related to the velocity will be poorly interpolated. <b>Only the position covariance should be considered in this
78       * case.</b>
79       *
80       * @param orbitInterpolator orbit interpolator
81       * @param outLOF output local orbital frame
82       */
83      public StateCovarianceKeplerianHermiteInterpolator(final TimeInterpolator<Orbit> orbitInterpolator,
84                                                         final LOFType outLOF) {
85          this(DEFAULT_INTERPOLATION_POINTS, orbitInterpolator, outLOF);
86      }
87  
88      /**
89       * Constructor using an output local orbital frame and :
90       * <ul>
91       *     <li>Default extrapolation threshold value ({@code DEFAULT_EXTRAPOLATION_THRESHOLD_SEC} s)</li>
92       *     <li>Use of position and two time derivatives during interpolation</li>
93       * </ul>
94       * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
95       * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
96       * phenomenon</a> and numerical problems (including NaN appearing).
97       * <p>
98       * <b>BEWARE:</b> If the output local orbital frame is not considered pseudo-inertial, all the covariance components
99       * related to the velocity will be poorly interpolated. <b>Only the position covariance should be considered in this
100      * case.</b>
101      *
102      * @param interpolationPoints number of interpolation points
103      * @param orbitInterpolator orbit interpolator
104      * @param outLOF output local orbital frame
105      */
106     public StateCovarianceKeplerianHermiteInterpolator(final int interpolationPoints,
107                                                        final TimeInterpolator<Orbit> orbitInterpolator,
108                                                        final LOFType outLOF) {
109         this(interpolationPoints, orbitInterpolator, CartesianDerivativesFilter.USE_PVA,
110              outLOF);
111     }
112 
113     /**
114      * Constructor using an output local orbital frame and :
115      * <ul>
116      *     <li>Use of position and two time derivatives during interpolation</li>
117      * </ul>
118      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
119      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
120      * phenomenon</a> and numerical problems (including NaN appearing).
121      * <p>
122      * <b>BEWARE:</b> If the output local orbital frame is not considered pseudo-inertial, all the covariance components
123      * related to the velocity will be poorly interpolated. <b>Only the position covariance should be considered in this
124      * case.</b>
125      *
126      * @param interpolationPoints number of interpolation points
127      * @param orbitInterpolator orbit interpolator
128      * @param outLOF output local orbital frame
129      * @param filter filter for derivatives from the sample to use in position-velocity-acceleration interpolation
130      */
131     public StateCovarianceKeplerianHermiteInterpolator(final int interpolationPoints,
132                                                        final TimeInterpolator<Orbit> orbitInterpolator,
133                                                        final CartesianDerivativesFilter filter,
134                                                        final LOFType outLOF) {
135         this(interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC, orbitInterpolator, filter, outLOF);
136     }
137 
138     /**
139      * Constructor using an output local orbital frame.
140      * <p>
141      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
142      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
143      * phenomenon</a> and numerical problems (including NaN appearing).
144      * <p>
145      * <b>BEWARE:</b> If the output local orbital frame is not considered pseudo-inertial, all the covariance components
146      * related to the velocity will be poorly interpolated. <b>Only the position covariance should be considered in this
147      * case.</b>
148      *
149      * @param interpolationPoints number of interpolation points
150      * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
151      * @param orbitInterpolator orbit interpolator
152      * @param outLOF output local orbital frame
153      * @param filter filter defining if only the state covariance value are used or if first or/and second Keplerian
154      * derivatives should be used during the interpolation.
155      */
156     public StateCovarianceKeplerianHermiteInterpolator(final int interpolationPoints, final double extrapolationThreshold,
157                                                        final TimeInterpolator<Orbit> orbitInterpolator,
158                                                        final CartesianDerivativesFilter filter, final LOFType outLOF) {
159         super(interpolationPoints, extrapolationThreshold, orbitInterpolator, outLOF);
160         this.filter = filter;
161     }
162 
163     /**
164      * Constructor using an output frame and :
165      * <ul>
166      *     <li>Default number of interpolation points of {@code DEFAULT_INTERPOLATION_POINTS}</li>
167      *     <li>Default extrapolation threshold value ({@code DEFAULT_EXTRAPOLATION_THRESHOLD_SEC} s)</li>
168      *     <li>Use of position and two time derivatives during interpolation</li>
169      * </ul>
170      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
171      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
172      * phenomenon</a> and numerical problems (including NaN appearing).
173      *
174      * @param orbitInterpolator orbit interpolator
175      * @param outFrame output frame
176      * @param outOrbitType output orbit type
177      * @param outPositionAngleType output position angle
178      */
179     public StateCovarianceKeplerianHermiteInterpolator(final TimeInterpolator<Orbit> orbitInterpolator, final Frame outFrame,
180                                                        final OrbitType outOrbitType, final PositionAngleType outPositionAngleType) {
181         this(DEFAULT_INTERPOLATION_POINTS, orbitInterpolator, outFrame, outOrbitType, outPositionAngleType);
182     }
183 
184     /**
185      * Constructor using an output frame and :
186      * <ul>
187      *     <li>Default number of interpolation points of {@code DEFAULT_INTERPOLATION_POINTS}</li>
188      *     <li>Use of position and two time derivatives during interpolation</li>
189      * </ul>
190      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
191      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
192      * phenomenon</a> and numerical problems (including NaN appearing).
193      *
194      * @param interpolationPoints number of interpolation points
195      * @param orbitInterpolator orbit interpolator
196      * @param outFrame output frame
197      * @param outOrbitType output orbit type
198      * @param outPositionAngleType output position angle
199      */
200     public StateCovarianceKeplerianHermiteInterpolator(final int interpolationPoints,
201                                                        final TimeInterpolator<Orbit> orbitInterpolator, final Frame outFrame,
202                                                        final OrbitType outOrbitType, final PositionAngleType outPositionAngleType) {
203         this(interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC, orbitInterpolator, CartesianDerivativesFilter.USE_PVA,
204              outFrame, outOrbitType, outPositionAngleType);
205     }
206 
207     /**
208      * Constructor using an output frame and :
209      * <ul>
210      *     <li>Default extrapolation threshold value ({@code DEFAULT_EXTRAPOLATION_THRESHOLD_SEC} s)</li>
211      * </ul>
212      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
213      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
214      * phenomenon</a> and numerical problems (including NaN appearing).
215      *
216      * @param interpolationPoints number of interpolation points
217      * @param orbitInterpolator orbit interpolator
218      * @param filter filter defining if only the state covariance value are used or if first or/and second Keplerian
219      * derivatives should be used during the interpolation.
220      * @param outFrame output frame
221      * @param outOrbitType output orbit type
222      * @param outPositionAngleType output position angle
223      */
224     public StateCovarianceKeplerianHermiteInterpolator(final int interpolationPoints,
225                                                        final TimeInterpolator<Orbit> orbitInterpolator,
226                                                        final CartesianDerivativesFilter filter, final Frame outFrame,
227                                                        final OrbitType outOrbitType, final PositionAngleType outPositionAngleType) {
228         this(interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC, orbitInterpolator, filter, outFrame, outOrbitType,
229                 outPositionAngleType);
230     }
231 
232     /**
233      * Constructor using an output frame.
234      * <p>
235      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
236      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
237      * phenomenon</a> and numerical problems (including NaN appearing).
238      *
239      * @param interpolationPoints number of interpolation points
240      * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
241      * @param orbitInterpolator orbit interpolator
242      * @param filter filter defining if only the state covariance value are used or if first or/and second Keplerian
243      * derivatives should be used during the interpolation.
244      * @param outFrame output frame
245      * @param outOrbitType output orbit type
246      * @param outPositionAngleType output position angle
247      */
248     public StateCovarianceKeplerianHermiteInterpolator(final int interpolationPoints, final double extrapolationThreshold,
249                                                        final TimeInterpolator<Orbit> orbitInterpolator,
250                                                        final CartesianDerivativesFilter filter, final Frame outFrame,
251                                                        final OrbitType outOrbitType, final PositionAngleType outPositionAngleType) {
252         super(interpolationPoints, extrapolationThreshold, orbitInterpolator, outFrame, outOrbitType, outPositionAngleType);
253         this.filter = filter;
254     }
255 
256     /** Get Filter defining if only the state covariance value are used or if first or/and second Keplerian derivatives
257      * should be used.
258      * @return Filter defining if only the state covariance value are used or if first or/and second Keplerian derivatives
259      * should be used.
260      */
261     public CartesianDerivativesFilter getFilter() {
262         return filter;
263     }
264 
265     /** {@inheritDoc} */
266     @Override
267     protected StateCovariance computeInterpolatedCovarianceInOrbitFrame(
268             final List<TimeStampedPair<Orbit, StateCovariance>> uncertainStates,
269             final Orbit interpolatedOrbit) {
270 
271         // Compute and combine covariances value and time derivatives
272         final List<double[][][]> covarianceValueAndDerivativesList = new ArrayList<>();
273         for (TimeStampedPair<Orbit, StateCovariance> uncertainState : uncertainStates) {
274             final double[][][] currentCovarianceValueAndDerivatives =
275                     computeAndCombineCovarianceValueAndDerivatives(uncertainState, interpolatedOrbit);
276 
277             covarianceValueAndDerivativesList.add(currentCovarianceValueAndDerivatives);
278         }
279 
280         // Interpolate covariance matrix in equinoctial elements
281         final RealMatrix interpolatedCovarianceMatrixInEqui =
282                 computeInterpolatedStateCovariance(interpolatedOrbit.getDate(),
283                                                    uncertainStates,
284                                                    covarianceValueAndDerivativesList);
285 
286         return new StateCovariance(interpolatedCovarianceMatrixInEqui,
287                                    interpolatedOrbit.getDate(), interpolatedOrbit.getFrame(),
288                                    OrbitType.EQUINOCTIAL, DEFAULT_POSITION_ANGLE);
289     }
290 
291     /**
292      * Compute and combine state covariance matrix and its two Keplerian time derivatives.
293      *
294      * @param uncertainState orbit and its associated covariance
295      * @param interpolatedOrbit interpolated orbit
296      *
297      * @return state covariance matrix and its two time derivatives
298      */
299     private double[][][] computeAndCombineCovarianceValueAndDerivatives(
300             final TimeStampedPair<Orbit, StateCovariance> uncertainState, final Orbit interpolatedOrbit) {
301 
302         // Get orbit and associated covariance
303         final Orbit           orbit      = uncertainState.getFirst();
304         final StateCovariance covariance = uncertainState.getSecond();
305 
306         // Express covariance in interpolated orbit frame for consistency among the sample
307         final StateCovariance covarianceInOrbitFrame = covariance.changeCovarianceFrame(orbit, interpolatedOrbit.getFrame());
308 
309         // Convert to equinoctial elements to avoid singularities
310         final StateCovariance covarianceInOrbitFrameInEqui =
311                 covarianceInOrbitFrame.changeCovarianceType(orbit, OrbitType.EQUINOCTIAL, DEFAULT_POSITION_ANGLE);
312 
313         // Get matrix
314         final RealMatrix covarianceInOrbitFrameInEquiMatrix = covarianceInOrbitFrameInEqui.getMatrix();
315 
316         // Compute covariance first and second time derivative according to instance filter
317         final int dim = StateCovariance.STATE_DIMENSION;
318 
319         final RealMatrix covarianceMatrixFirstDerInKep;
320         final RealMatrix covarianceMatrixSecondDerInKep;
321 
322         switch (filter) {
323             case USE_P:
324                 covarianceMatrixFirstDerInKep = MatrixUtils.createRealMatrix(dim, dim);
325                 covarianceMatrixSecondDerInKep = MatrixUtils.createRealMatrix(dim, dim);
326                 break;
327             case USE_PV:
328                 covarianceMatrixFirstDerInKep = computeCovarianceFirstDerivative(orbit, covarianceInOrbitFrameInEquiMatrix);
329                 covarianceMatrixSecondDerInKep = MatrixUtils.createRealMatrix(dim, dim);
330                 break;
331             case USE_PVA:
332                 covarianceMatrixFirstDerInKep = computeCovarianceFirstDerivative(orbit, covarianceInOrbitFrameInEquiMatrix);
333                 covarianceMatrixSecondDerInKep =
334                         computeCovarianceSecondDerivative(orbit, covarianceInOrbitFrameInEquiMatrix);
335                 break;
336             default:
337                 // Should never happen
338                 throw new OrekitInternalError(null);
339         }
340 
341         // Combine and output the state covariance and its first two time derivative in a single array
342         return combineCovarianceValueAndDerivatives(covarianceInOrbitFrameInEquiMatrix,
343                                                     covarianceMatrixFirstDerInKep,
344                                                     covarianceMatrixSecondDerInKep);
345     }
346 
347     /**
348      * Compute interpolated state covariance in equinoctial elements using a Hermite interpolator.
349      *
350      * @param interpolationDate interpolation date
351      * @param uncertainStates list of orbits and their associated covariances
352      * @param covarianceValueAndDerivativesList list of covariances and their associated first and second time derivatives
353      *
354      * @return interpolated state covariance in equinoctial elements
355      *
356      * @see HermiteInterpolator
357      */
358     private RealMatrix computeInterpolatedStateCovariance(final AbsoluteDate interpolationDate,
359                                                           final List<TimeStampedPair<Orbit, StateCovariance>> uncertainStates,
360                                                           final List<double[][][]> covarianceValueAndDerivativesList) {
361 
362         final RealMatrix interpolatedCovarianceMatrix = new BlockRealMatrix(new double[ROW_DIM][COLUMN_DIM]);
363 
364         // Interpolate each element in the covariance matrix
365         for (int i = 0; i < ROW_DIM; i++) {
366             for (int j = 0; j < COLUMN_DIM; j++) {
367 
368                 // Create an interpolator for each element
369                 final HermiteInterpolator tempInterpolator = new HermiteInterpolator();
370 
371                 // Fill interpolator with all samples value and associated derivatives
372                 for (int k = 0; k < uncertainStates.size(); k++) {
373                     final TimeStampedPair<Orbit, StateCovariance> currentUncertainStates = uncertainStates.get(k);
374 
375                     final double[][][] currentCovarianceValueAndDerivatives = covarianceValueAndDerivativesList.get(k);
376 
377                     final double deltaT = currentUncertainStates.getDate().durationFrom(interpolationDate);
378 
379                     addSampleToInterpolator(tempInterpolator, deltaT, currentCovarianceValueAndDerivatives[i][j]);
380                 }
381 
382                 // Interpolate
383                 interpolatedCovarianceMatrix.setEntry(i, j, tempInterpolator.value(0)[0]);
384             }
385         }
386 
387         return interpolatedCovarianceMatrix;
388     }
389 
390     /**
391      * Add sample to given interpolator.
392      *
393      * @param interpolator interpolator to add sample to
394      * @param deltaT abscissa for interpolation
395      * @param valueAndDerivatives value and associated derivatives to add
396      */
397     private void addSampleToInterpolator(final HermiteInterpolator interpolator, final double deltaT,
398                                          final double[] valueAndDerivatives) {
399         switch (filter) {
400             case USE_P:
401                 interpolator.addSamplePoint(deltaT, new double[] { valueAndDerivatives[0] });
402                 break;
403             case USE_PV:
404                 interpolator.addSamplePoint(deltaT,
405                                             new double[] { valueAndDerivatives[0] },
406                                             new double[] { valueAndDerivatives[1] });
407                 break;
408             case USE_PVA:
409                 interpolator.addSamplePoint(deltaT,
410                                             new double[] { valueAndDerivatives[0] },
411                                             new double[] { valueAndDerivatives[1] },
412                                             new double[] { valueAndDerivatives[2] });
413                 break;
414             default:
415                 // Should never happen
416                 throw new OrekitInternalError(null);
417         }
418     }
419 
420     /**
421      * Compute state covariance first Keplerian time derivative.
422      *
423      * @param orbit orbit
424      * @param covarianceMatrixInEqui state covariance matrix in equinoctial elements
425      *
426      * @return state covariance first time derivative
427      */
428     private RealMatrix computeCovarianceFirstDerivative(final Orbit orbit,
429                                                         final RealMatrix covarianceMatrixInEqui) {
430 
431         final RealMatrix covarianceFirstDerivative = new BlockRealMatrix(ROW_DIM, COLUMN_DIM);
432 
433         // Compute common term used in papers
434         final double m = orbit.getMeanAnomalyDotWrtA();
435 
436         // Compute first time derivative of each element in the covariance matrix
437         for (int i = 0; i < ROW_DIM; i++) {
438             for (int j = 0; j < COLUMN_DIM; j++) {
439                 if (i != 5 && j != 5) {
440                     covarianceFirstDerivative.setEntry(i, j, 0);
441                 }
442                 else if (i == 5 && j != 5) {
443 
444                     final double value = covarianceMatrixInEqui.getEntry(0, j) * m;
445 
446                     covarianceFirstDerivative.setEntry(i, j, value);
447                     covarianceFirstDerivative.setEntry(j, i, value);
448                 }
449                 else {
450                     final double value = 2 * covarianceMatrixInEqui.getEntry(0, 5) * m;
451 
452                     covarianceFirstDerivative.setEntry(i, j, value);
453                 }
454             }
455         }
456 
457         return covarianceFirstDerivative;
458 
459     }
460 
461     /**
462      * Compute state covariance second Keplerian time derivative.
463      *
464      * @param orbit orbit
465      * @param covarianceMatrixInEqui state covariance matrix in equinoctial elements
466      *
467      * @return state covariance second time derivative
468      */
469     private RealMatrix computeCovarianceSecondDerivative(final Orbit orbit,
470                                                          final RealMatrix covarianceMatrixInEqui) {
471 
472         final RealMatrix covarianceSecondDerivative = new BlockRealMatrix(ROW_DIM, COLUMN_DIM);
473 
474         // Compute common term used in papers
475         final double m = orbit.getMeanAnomalyDotWrtA();
476 
477         // Compute second time derivative of each element in the covariance matrix
478         for (int i = 0; i < ROW_DIM; i++) {
479             for (int j = 0; j < COLUMN_DIM; j++) {
480                 if (i == 5 && j == 5) {
481 
482                     final double value = 2 * covarianceMatrixInEqui.getEntry(0, 0) * m * m;
483 
484                     covarianceSecondDerivative.setEntry(i, j, value);
485                 }
486                 else {
487                     covarianceSecondDerivative.setEntry(i, j, 0);
488                 }
489             }
490         }
491 
492         return covarianceSecondDerivative;
493 
494     }
495 
496     /**
497      * Combine state covariance matrix and its two Keplerian time derivatives.
498      *
499      * @param covarianceMatrixInEqui covariance matrix in equinoctial elements
500      * @param covarianceMatrixFirstDerInEqui covariance matrix first time derivative in equinoctial elements
501      * @param covarianceMatrixSecondDerInEqui covariance matrix second time derivative in equinoctial elements
502      *
503      * @return state covariance matrix and its two time derivatives
504      */
505     private double[][][] combineCovarianceValueAndDerivatives(final RealMatrix covarianceMatrixInEqui,
506                                                               final RealMatrix covarianceMatrixFirstDerInEqui,
507                                                               final RealMatrix covarianceMatrixSecondDerInEqui) {
508 
509         final double[][][] covarianceValueAndDerivativesArray = new double[ROW_DIM][COLUMN_DIM][3];
510 
511         // Combine covariance and its first two time derivatives in a single 3D array
512         for (int i = 0; i < ROW_DIM; i++) {
513             for (int j = 0; j < COLUMN_DIM; j++) {
514                 covarianceValueAndDerivativesArray[i][j][0] = covarianceMatrixInEqui.getEntry(i, j);
515                 covarianceValueAndDerivativesArray[i][j][1] = covarianceMatrixFirstDerInEqui.getEntry(i, j);
516                 covarianceValueAndDerivativesArray[i][j][2] = covarianceMatrixSecondDerInEqui.getEntry(i, j);
517             }
518         }
519 
520         return covarianceValueAndDerivativesArray;
521     }
522 }