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  
18  package org.orekit.files.ccsds.ndm.odm;
19  
20  import java.util.Optional;
21  import java.util.function.Supplier;
22  
23  import org.hipparchus.linear.MatrixUtils;
24  import org.hipparchus.linear.RealMatrix;
25  import org.orekit.annotation.Nullable;
26  import org.orekit.errors.OrekitException;
27  import org.orekit.errors.OrekitMessages;
28  import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
29  import org.orekit.files.ccsds.definitions.FrameFacade;
30  import org.orekit.files.ccsds.section.CommentsContainer;
31  import org.orekit.files.ccsds.section.Data;
32  import org.orekit.frames.Frame;
33  import org.orekit.time.AbsoluteDate;
34  
35  /** Container for OPM/OMM/OCM Cartesian covariance matrix.
36   * <p>
37   * Beware that the Orekit getters and setters all rely on SI units. The parsers
38   * and writers take care of converting these SI units into CCSDS mandatory units.
39   * The {@link org.orekit.utils.units.Unit Unit} class provides useful
40   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
41   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
42   * already use CCSDS units instead of the API SI units. The general-purpose
43   * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
44   * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
45   * (with an 's') also provide some predefined units. These predefined units and the
46   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
47   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
48   * what the parsers and writers use for the conversions.
49   * </p>
50   * @author sports
51   * @since 6.1
52   */
53  public class CartesianCovariance extends CommentsContainer implements Data {
54  
55      /** Labels for matrix row/columns. */
56      private static final String[] LABELS = {
57          "X", "Y", "Z", "X_DOT", "Y_DOT", "Z_DOT"
58      };
59  
60      /** Supplier for default reference frame. */
61      private final Supplier<FrameFacade> defaultFrameSupplier;
62  
63      /** For creating a {@link Frame}. */
64      private final CcsdsFrameMapper frameMapper;
65  
66      /** Matrix epoch. */
67      private AbsoluteDate epoch;
68  
69      /** Reference frame in which data are given. */
70      @Nullable
71      private FrameFacade referenceFrame;
72  
73      /** Position/Velocity covariance matrix. */
74      private final RealMatrix covarianceMatrix;
75  
76      /**
77       * Create an empty data set.
78       *
79       * @param defaultFrameSupplier supplier for default reference frame if no
80       *                             frame is specified in the CCSDS message
81       * @param frameMapper          for creating a {@link Frame}.
82       * @since 13.1.5
83       */
84      public CartesianCovariance(final Supplier<FrameFacade> defaultFrameSupplier,
85                                 final CcsdsFrameMapper frameMapper) {
86          this.defaultFrameSupplier = defaultFrameSupplier;
87          this.frameMapper = frameMapper;
88          covarianceMatrix = MatrixUtils.createRealMatrix(6, 6);
89          for (int i = 0; i < covarianceMatrix.getRowDimension(); ++i) {
90              for (int j = 0; j <= i; ++j) {
91                  covarianceMatrix.setEntry(i, j, Double.NaN);
92              }
93          }
94      }
95  
96      /** {@inheritDoc} */
97      @Override
98      public void validate(final double version) {
99          super.validate(version);
100         checkNotNull(epoch, CartesianCovarianceKey.EPOCH.name());
101         for (int i = 0; i < covarianceMatrix.getRowDimension(); ++i) {
102             for (int j = 0; j <= i; ++j) {
103                 if (Double.isNaN(covarianceMatrix.getEntry(i, j))) {
104                     throw new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
105                                               "C" + LABELS[i] + "_" + LABELS[j]);
106                 }
107             }
108         }
109     }
110 
111     /** Get matrix epoch.
112      * @return matrix epoch
113      */
114     public AbsoluteDate getEpoch() {
115         return epoch;
116     }
117 
118     /** Set matrix epoch.
119      * @param epoch matrix epoch
120      */
121     public void setEpoch(final AbsoluteDate epoch) {
122         refuseFurtherComments();
123         this.epoch = epoch;
124     }
125 
126     /**
127      * Get the reference frame, falling back to the default if not explicitly set.
128      *
129      * @return The reference frame specified by the {@code COV_REF_FRAME} keyword
130      * or inherited from metadata
131      */
132     public FrameFacade getReferenceFrame() {
133         return Optional.ofNullable(referenceFrame).orElse(defaultFrameSupplier.get());
134     }
135 
136     /** Set the reference frame in which data are given.
137      * @param referenceFrame the reference frame to be set
138      */
139     public void setReferenceFrame(final FrameFacade referenceFrame) {
140         refuseFurtherComments();
141         this.referenceFrame = referenceFrame;
142     }
143 
144     /**
145      * Get the mapping between a CCSDS frame and a {@link Frame}.
146      *
147      * @return the frame mapper.
148      * @since 13.1.5
149      */
150     public CcsdsFrameMapper getFrameMapper() {
151         return frameMapper;
152     }
153 
154     /**
155      * Get the frame in which this covariance matrix is defined. Note that only
156      * the orientation of the returned frame is significant, the position of the
157      * returned frame is irrelevant and should be ignored.
158      *
159      * @return Orekit frame for this covariance matrix.
160      * @see #getReferenceFrame()
161      * @see #getFrameMapper()
162      * @since 13.1.5
163      */
164     public Frame getFrame() {
165         // OEM, OMM, and OPM don't allow a COV_FRAME_EPOCH, but OCM does.
166         // This class is not used for OCM, which allows non-Cartesian covariance
167         return getFrameMapper().buildCcsdsFrame(getReferenceFrame(), null);
168     }
169 
170     /** Get the Position/Velocity covariance matrix.
171      * @return the Position/Velocity covariance matrix
172      */
173     public RealMatrix getCovarianceMatrix() {
174         return covarianceMatrix;
175     }
176 
177     /** Set an entry in the Position/Velocity covariance matrix.
178      * <p>
179      * Both m(j, k) and m(k, j) are set.
180      * </p>
181      * @param j row index (must be between 0 and 5 (inclusive)
182      * @param k column index (must be between 0 and 5 (inclusive)
183      * @param entry value of the matrix entry
184      */
185     public void setCovarianceMatrixEntry(final int j, final int k, final double entry) {
186         refuseFurtherComments();
187         covarianceMatrix.setEntry(j, k, entry);
188         covarianceMatrix.setEntry(k, j, entry);
189     }
190 
191 }