1   /* Copyright 2002-2024 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.ocm;
19  
20  import java.io.IOException;
21  import java.util.List;
22  
23  import org.hipparchus.linear.RealMatrix;
24  import org.hipparchus.util.FastMath;
25  import org.orekit.files.ccsds.definitions.TimeConverter;
26  import org.orekit.files.ccsds.section.AbstractWriter;
27  import org.orekit.files.ccsds.utils.FileFormat;
28  import org.orekit.files.ccsds.utils.generation.Generator;
29  import org.orekit.utils.AccurateFormatter;
30  import org.orekit.utils.units.Unit;
31  
32  /** Writer for covariance history data.
33   * @author Luc Maisonobe
34   * @since 11.0
35   */
36  class OrbitCovarianceHistoryWriter extends AbstractWriter {
37  
38      /** Covariance history block. */
39      private final OrbitCovarianceHistory history;
40  
41      /** Converter for dates. */
42      private final TimeConverter timeConverter;
43  
44      /** Create a writer.
45       * @param covarianceHistory covariance history to write
46       * @param timeConverter converter for dates
47       */
48      OrbitCovarianceHistoryWriter(final OrbitCovarianceHistory covarianceHistory,
49                              final TimeConverter timeConverter) {
50          super(OcmDataSubStructureKey.cov.name(), OcmDataSubStructureKey.COV.name());
51          this.history       = covarianceHistory;
52          this.timeConverter = timeConverter;
53      }
54  
55      /** {@inheritDoc} */
56      @Override
57      protected void writeContent(final Generator generator) throws IOException {
58  
59          // covariance history block
60          final OrbitCovarianceHistoryMetadata metadata = history.getMetadata();
61          generator.writeComments(metadata.getComments());
62  
63          // identifiers
64          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_ID.name(),       metadata.getCovID(),      null, false);
65          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_PREV_ID.name(),  metadata.getCovPrevID(),  null, false);
66          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_NEXT_ID.name(),  metadata.getCovNextID(),  null, false);
67          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_BASIS.name(),    metadata.getCovBasis(),   null, false);
68          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_BASIS_ID.name(), metadata.getCovBasisID(), null, false);
69  
70          // references
71          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_REF_FRAME.name(),   metadata.getCovReferenceFrame().getName(),  null, false);
72          if (!metadata.getCovFrameEpoch().equals(timeConverter.getReferenceDate()) &&
73              metadata.getCovReferenceFrame().asOrbitRelativeFrame() == null &&
74              metadata.getCovReferenceFrame().asSpacecraftBodyFrame() == null) {
75              generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_FRAME_EPOCH.name(), timeConverter, metadata.getCovFrameEpoch(), true, false);
76          }
77  
78          // scaling
79          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_SCALE_MIN.name(),  metadata.getCovScaleMin(), Unit.ONE,       false);
80          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_SCALE_MAX.name(),  metadata.getCovScaleMax(), Unit.ONE,       false);
81          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_CONFIDENCE.name(), metadata.getCovConfidence(), Unit.PERCENT, false);
82  
83          // elements
84          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_TYPE.name(),     metadata.getCovType(),                                     false);
85          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_ORDERING.name(), metadata.getCovOrdering(),                                 false);
86          generator.writeEntry(OrbitCovarianceHistoryMetadataKey.COV_UNITS.name(),    generator.unitsListToString(metadata.getCovUnits()), null, false);
87  
88          // data
89          final List<Unit> units = metadata.getCovType().getUnits();
90          for (final OrbitCovariance covariance : history.getCovariances()) {
91              final RealMatrix        matrix   = covariance.getMatrix();
92              final Ordering          ordering = metadata.getCovOrdering();
93              final CovarianceIndexer indexer  = new CovarianceIndexer(units.size());
94              final StringBuilder     line     = new StringBuilder();
95              line.append(generator.dateToString(timeConverter, covariance.getDate()));
96              for (int k = 0; k < ordering.nbElements(units.size()); ++k) {
97                  final int i = indexer.getRow();
98                  final int j = indexer.getColumn();
99                  final double cij;
100                 if (indexer.isCrossCorrelation()) {
101                     // we need to compute the cross-correlation
102                     cij = matrix.getEntry(i, j) /
103                                     FastMath.sqrt(matrix.getEntry(i, i) * matrix.getEntry(j, j));
104                 } else {
105                     // we need to get the covariance
106                     cij = units.get(i).fromSI(units.get(j).fromSI(matrix.getEntry(i, j)));
107                 }
108                 line.append(' ');
109                 line.append(AccurateFormatter.format(cij));
110                 ordering.update(indexer);
111             }
112             if (generator.getFormat() == FileFormat.XML) {
113                 generator.writeEntry(Ocm.COV_LINE, line.toString(), null, true);
114             } else {
115                 generator.writeRawData(line);
116                 generator.newLine();
117             }
118 
119         }
120 
121     }
122 
123 }