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.files.ccsds.ndm.cdm;
18  
19  import java.util.List;
20  
21  import org.orekit.annotation.DefaultDataContext;
22  import org.orekit.bodies.CelestialBody;
23  import org.orekit.bodies.CelestialBodyFactory;
24  import org.orekit.data.DataContext;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.files.ccsds.definitions.YesNoUnknown;
28  import org.orekit.files.ccsds.definitions.BodyFacade;
29  import org.orekit.files.ccsds.definitions.FrameFacade;
30  import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
31  import org.orekit.files.ccsds.definitions.ModifiedFrame;
32  import org.orekit.files.ccsds.definitions.TimeSystem;
33  import org.orekit.files.ccsds.ndm.odm.ocm.ObjectType;
34  import org.orekit.files.ccsds.section.Metadata;
35  import org.orekit.frames.Frame;
36  
37  /**
38   * This class gathers the meta-data present in the Conjunction Data Message (CDM).
39   * @author Melina Vanel
40   * @since 11.2
41   */
42  public class CdmMetadata extends Metadata {
43  
44      /** CDM relative metadata. */
45      private CdmRelativeMetadata relativeMetadata;
46  
47      /** Refering to object 1 or 2. */
48      private String object;
49  
50      /** Unique satellite identification designator for the object. */
51      private String objectDesignator;
52  
53      /** Specification of satellite catalog source. */
54      private String catalogName;
55  
56      /** Object name. */
57      private String objectName;
58  
59      /** International designator for the object as assigned by the UN Committee
60       * on Space Research (COSPAR) and the US National Space Science Data Center (NSSDC). */
61      private String internationalDesignator;
62  
63      /** Type of object. */
64      private ObjectType objectType;
65  
66      /** Operator contact position for the space object. */
67      private String operatorContact;
68  
69      /** Operator organization for the space object. */
70      private String operatorOrganization;
71  
72      /** Operator phone for the space object. */
73      private String operatorPhone;
74  
75      /** Operator email for the space object. */
76      private String operatorEmail;
77  
78      /** Unique identifier of Orbit Data Message(s) that are linked (relevant) to this Conjunction Data Message. */
79      private String odmMsgLink;
80  
81      /** Unique identifier of Attitude Data Message(s) that are linked (relevant) to this Conjunction Data Message. */
82      private String admMsgLink;
83  
84      /** Unique name of the external ephemeris file used for the object or NONE. */
85      private String ephemName;
86  
87      /** Flag indicating whether new tracking observations are anticipated prior to the issue of the next CDM associated with the event
88       * specified by CONJUNCTION_ID. */
89      private YesNoUnknown obsBeforeNextMessage;
90  
91      /** Operator email for the space object. */
92      private CovarianceMethod covarianceMethod;
93  
94      /** Maneuver capacity. */
95      private Maneuvrable maneuverable;
96  
97      /** Central body around which Object1 and 2 are orbiting. */
98      private BodyFacade orbitCenter;
99  
100     /** Reference frame in which state vector data are given. */
101     private FrameFacade refFrame;
102 
103     /** Gravity model name. */
104     private String gravityModel;
105 
106     /** Degree of the gravity model. */
107     private int gravityDegree;
108 
109     /** Order of the gravity model. */
110     private int gravityOrder;
111 
112     /** Name of atmospheric model. */
113     private String atmosphericModel;
114 
115     /** N-body perturbation bodies. */
116     private List<BodyFacade> nBodyPerturbations;
117 
118     /** Is solar radiation pressure taken into account or not ? STANDARD CCSDS saying YES/NO choice and optional */
119     private YesNoUnknown isSolarRadPressure;
120 
121     /** Is solid Earth and ocean tides taken into account or not. STANDARD CCSDS saying YES/NO choice and optional */
122     private YesNoUnknown isEarthTides;
123 
124     /** Is in-track thrust modelling used or not. STANDARD CCSDS saying YES/NO choice and optional */
125     private YesNoUnknown isIntrackThrustModeled;
126 
127     /** The source from which the covariance data used in the report for both Object 1 and Object 2 originates. */
128     private String covarianceSource;
129 
130     /** Flag indicating the type of alternate covariance information provided. */
131     private AltCovarianceType altCovType;
132 
133     /** Reference frame in which the alternate covariance data are given. */
134     private FrameFacade altCovRefFrame;
135 
136     /** Simple constructor.
137      */
138     @DefaultDataContext
139     public CdmMetadata() {
140         super(null);
141         orbitCenter = new BodyFacade(CelestialBodyFactory.EARTH.toUpperCase(), CelestialBodyFactory.getEarth());
142     }
143 
144     /** Simple constructor.
145      *
146      * @param dataContext data context
147      */
148     public CdmMetadata(final DataContext dataContext) {
149         super(null);
150         final CelestialBody earth = dataContext.getCelestialBodies().getEarth();
151         orbitCenter = new BodyFacade(earth.getName().toUpperCase(), earth);
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     public void validate(final double version) {
157         // We only check values that are mandatory in a cdm file
158         checkNotNull(object,                  CdmMetadataKey.OBJECT.name());
159         checkNotNull(objectDesignator,        CdmMetadataKey.OBJECT_DESIGNATOR.name());
160         checkNotNull(catalogName,             CdmMetadataKey.CATALOG_NAME.name());
161         checkNotNull(objectName,              CdmMetadataKey.OBJECT_NAME.name());
162         checkNotNull(internationalDesignator, CdmMetadataKey.INTERNATIONAL_DESIGNATOR.name());
163         checkNotNull(ephemName,               CdmMetadataKey.EPHEMERIS_NAME.name());
164         checkNotNull(covarianceMethod,        CdmMetadataKey.COVARIANCE_METHOD.name());
165         checkNotNull(maneuverable,            CdmMetadataKey.MANEUVERABLE.name());
166         checkNotNull(refFrame,                CdmMetadataKey.REF_FRAME.name());
167     }
168 
169     /**
170      * Get the relative metadata following header, they are the common metadata for the CDM.
171      * @return relativeMetadata relative metadata
172      */
173     public CdmRelativeMetadata getRelativeMetadata() {
174         return relativeMetadata;
175     }
176 
177     /**
178      * Set the relative metadata following header, they are the common metadata for the CDM.
179      * @param relativeMetadata relative metadata
180      */
181     public void setRelativeMetadata(final CdmRelativeMetadata relativeMetadata) {
182         this.relativeMetadata = relativeMetadata;
183     }
184 
185     /**
186      * Get the object name for which metadata are given.
187      * @return the object name
188      */
189     public String getObject() {
190         return object;
191     }
192 
193     /**
194      * Set the object name for which metadata are given.
195      * @param object = object 1 or 2 to be set
196      */
197     public void setObject(final String object) {
198         this.setTimeSystem(TimeSystem.UTC);
199         refuseFurtherComments();
200         this.object = object;
201     }
202 
203     /**
204      * Get the object satellite catalog designator for which metadata are given.
205      * @return the satellite catalog designator for the object
206      */
207     public String getObjectDesignator() {
208         return objectDesignator;
209     }
210 
211     /**
212      * Set the satellite designator for the object for which metadata are given.
213      * @param objectDesignator for the spacecraft to be set
214      */
215     public void setObjectDesignator(final String objectDesignator) {
216         refuseFurtherComments();
217         this.objectDesignator = objectDesignator;
218     }
219 
220     /**
221      * Get the satellite catalog used for the object.
222      * @return the catalog name
223      */
224     public String getCatalogName() {
225         return catalogName;
226     }
227 
228     /**
229      * Set the satellite catalog name used for object.
230      * @param catalogName for the spacecraft to be set
231      */
232     public void setCatalogName(final String catalogName) {
233         refuseFurtherComments();
234         this.catalogName = catalogName;
235     }
236 
237     /**
238      * Get the spacecraft name for the object.
239      * @return the spacecraft name
240      */
241     public String getObjectName() {
242         return objectName;
243     }
244 
245     /**
246      * Set the spacecraft name used for object.
247      * @param objectName for the spacecraft to be set
248      */
249     public void setObjectName(final String objectName) {
250         refuseFurtherComments();
251         this.objectName = objectName;
252     }
253 
254     /**
255      * Get the international designator for the object.
256      * @return the international designator
257      */
258     public String getInternationalDes() {
259         return internationalDesignator;
260     }
261 
262     /**
263      * Set the international designator used for object.
264      * @param internationalDes for the object to be set
265      */
266     public void setInternationalDes(final String internationalDes) {
267         refuseFurtherComments();
268         this.internationalDesignator = internationalDes;
269     }
270 
271     /**
272      * Get the type of object.
273      * @return the object type
274      */
275     public ObjectType getObjectType() {
276         return objectType;
277     }
278 
279     /**
280      * Set the type of object.
281      * @param objectType type of object
282      */
283     public void setObjectType(final ObjectType objectType) {
284         refuseFurtherComments();
285         this.objectType = objectType;
286     }
287 
288     /**
289      * Get the contact position of the owner / operator of the object.
290      * @return the contact position
291      */
292     public String getOperatorContactPosition() {
293         return operatorContact;
294     }
295 
296     /**
297      * Set the contact position for the object owner / operator.
298      * @param opContact for the object to be set
299      */
300     public void setOperatorContactPosition(final String opContact) {
301         refuseFurtherComments();
302         this.operatorContact = opContact;
303     }
304 
305     /**
306      * Get the contact organisation of the object.
307      * @return the contact organisation
308      */
309     public String getOperatorOrganization() {
310         return operatorOrganization;
311     }
312 
313     /**
314      * Set the contact organisation of the object.
315      * @param operatorOrganization contact organisation for the object to be set
316      */
317     public void setOperatorOrganization(final String operatorOrganization) {
318         refuseFurtherComments();
319         this.operatorOrganization = operatorOrganization;
320     }
321 
322     /**
323      * Get the contact phone of the operator of the object.
324      * @return the operator phone
325      */
326     public String getOperatorPhone() {
327         return operatorPhone;
328     }
329 
330     /**
331      * Set the operator phone of the object.
332      * @param operatorPhone contact phone for the object to be set
333      */
334     public void setOperatorPhone(final String operatorPhone) {
335         refuseFurtherComments();
336         this.operatorPhone = operatorPhone;
337     }
338 
339     /**
340      * Get the email of the operator of the object.
341      * @return the operator email
342      */
343     public String getOperatorEmail() {
344         return operatorEmail;
345     }
346 
347     /**
348      * Set the object operator email.
349      * @param operatorEmail operator email for the object to be set
350      */
351     public void setOperatorEmail(final String operatorEmail) {
352         refuseFurtherComments();
353         this.operatorEmail = operatorEmail;
354     }
355 
356     /**
357      * Get the unique name of the external ephemeris used for OD.
358      * @return the name of ephemeris used
359      */
360     public String getEphemName() {
361         return ephemName;
362     }
363 
364     /**
365      * Set the name of external ephemeris used for OD.
366      * @param ephemName me of external ephemeris used
367      */
368     public void setEphemName(final String ephemName) {
369         refuseFurtherComments();
370         this.ephemName = ephemName;
371     }
372 
373     /**
374      * Get the method name used to calculate covariance during OD.
375      * @return the name of covariance calculation method
376      */
377     public CovarianceMethod getCovarianceMethod() {
378         return covarianceMethod;
379     }
380 
381     /**
382      * Set the method name used to calculate covariance during OD.
383      * @param covarianceMethod method name for covariance calculation
384      */
385     public void setCovarianceMethod(final CovarianceMethod covarianceMethod) {
386         refuseFurtherComments();
387         this.covarianceMethod = covarianceMethod;
388     }
389 
390     /**
391      * Get the ability of object to maneuver or not.
392      * @return the ability to maneuver
393      */
394     public Maneuvrable getManeuverable() {
395         return maneuverable;
396     }
397 
398     /**
399      * Set the object maneuver ability.
400      * @param maneuverable ability to maneuver
401      */
402     public void setManeuverable(final Maneuvrable maneuverable) {
403         refuseFurtherComments();
404         this.maneuverable = maneuverable;
405     }
406 
407     /**
408      * Get the central body for object 1 and 2.
409      * @return the name of the central body
410      */
411     public BodyFacade getOrbitCenter() {
412         return orbitCenter;
413     }
414 
415     /**
416      * Set the central body name for object 1 and 2.
417      * @param orbitCenter name of the central body
418      */
419     public void setOrbitCenter(final BodyFacade orbitCenter) {
420         refuseFurtherComments();
421         this.orbitCenter = orbitCenter;
422     }
423 
424     /**
425      * Get the reference frame in which data are given: used for state vector and
426      * Keplerian elements data (and for the covariance reference frame if none is given).
427      *
428      * @return the reference frame
429      */
430     public Frame getFrame() {
431         if (orbitCenter == null || orbitCenter.getBody() == null) {
432             throw new OrekitException(OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY, "No Orbit center name");
433         }
434         if (refFrame == null) {
435             throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, "No reference frame");
436         }
437         else  {
438             if (refFrame.asFrame() == null) {
439                 throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, refFrame.getName());
440             }
441         }
442         // Just return frame if we don't need to shift the center based on CENTER_NAME
443         // MCI and ICRF are the only non-Earth centered frames specified in Annex A.
444         final boolean isMci  = refFrame.asCelestialBodyFrame() == CelestialBodyFrame.MCI;
445         final boolean isIcrf = refFrame.asCelestialBodyFrame() == CelestialBodyFrame.ICRF;
446         final boolean isSolarSystemBarycenter =
447                 CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER.equals(orbitCenter.getBody().getName());
448         if (!(isMci || isIcrf) && CelestialBodyFactory.EARTH.equals(orbitCenter.getBody().getName()) ||
449             isMci && CelestialBodyFactory.MARS.equals(orbitCenter.getBody().getName()) ||
450             isIcrf && isSolarSystemBarycenter) {
451             return refFrame.asFrame();
452         }
453         // else, translate frame to specified center.
454         return new ModifiedFrame(refFrame.asFrame(), refFrame.asCelestialBodyFrame(),
455                                  orbitCenter.getBody(), orbitCenter.getName());
456     }
457 
458     /**
459      * Get the value of {@code REF_FRAME} as an Orekit {@link Frame}. The {@code
460      * ORBIT_CENTER} key word has not been applied yet, so the returned frame may not
461      * correspond to the reference frame of the data in the file.
462      * @return the reference frame
463      */
464     public FrameFacade getRefFrame() {
465         return refFrame;
466     }
467 
468     /**
469      * Set the name of the reference frame in which the state vector data are given.
470      * @param refFrame reference frame
471      */
472     public void setRefFrame(final FrameFacade refFrame) {
473         refuseFurtherComments();
474         this.refFrame = refFrame;
475     }
476 
477     /** Get gravity model name.
478      * @return gravity model name
479      */
480     public String getGravityModel() {
481         return gravityModel;
482     }
483 
484     /** Get degree of the gravity model.
485      * @return degree of the gravity model
486      */
487     public int getGravityDegree() {
488         return gravityDegree;
489     }
490 
491     /** Get order of the gravity model.
492      * @return order of the gravity model
493      */
494     public int getGravityOrder() {
495         return gravityOrder;
496     }
497 
498     /** Set gravity model.
499      * @param name name of the model
500      * @param degree degree of the model
501      * @param order order of the model
502      */
503     public void setGravityModel(final String name, final int degree, final int order) {
504         refuseFurtherComments();
505         this.gravityModel  = name;
506         this.gravityDegree = degree;
507         this.gravityOrder  = order;
508     }
509 
510     /** Get name of atmospheric model.
511      * @return name of atmospheric model
512      */
513     public String getAtmosphericModel() {
514         return atmosphericModel;
515     }
516 
517     /** Set name of atmospheric model.
518      * @param atmosphericModel name of atmospheric model
519      */
520     public void setAtmosphericModel(final String atmosphericModel) {
521         refuseFurtherComments();
522         this.atmosphericModel = atmosphericModel;
523     }
524 
525     /** Get n-body perturbation bodies.
526      * @return n-body perturbation bodies
527      */
528     public List<BodyFacade> getNBodyPerturbations() {
529         return nBodyPerturbations;
530     }
531 
532     /** Set n-body perturbation bodies.
533      * @param nBody n-body perturbation bodies
534      */
535     public void setNBodyPerturbations(final List<BodyFacade> nBody) {
536         refuseFurtherComments();
537         this.nBodyPerturbations = nBody;
538     }
539 
540     /**
541      * Get Enum YesNoUnknown that indicates if Solar Radiation Pressure is taken into account or not.
542      * @return isSolarRadPressure YesNoUnknown
543      */
544     public YesNoUnknown getSolarRadiationPressure() {
545         return isSolarRadPressure;
546     }
547 
548     /**
549      * Set Enum that indicates if Solar Radiation Pressure is taken into account or not.
550      * @param isSolRadPressure YesNoUnknown
551      */
552     public void setSolarRadiationPressure(final YesNoUnknown isSolRadPressure) {
553         refuseFurtherComments();
554         this.isSolarRadPressure = isSolRadPressure;
555     }
556 
557     /**
558      * Get Enum YesNoUnknown that indicates if Earth and ocean tides are taken into account or not.
559      * @return isEarthTides YesNoUnknown
560      */
561     public YesNoUnknown getEarthTides() {
562         return isEarthTides;
563     }
564 
565     /**
566      * Set Enum YesNoUnknown that indicates if Earth and ocean tides are taken into account or not.
567      * @param EarthTides YesNoUnknown
568      */
569     public void setEarthTides(final YesNoUnknown EarthTides) {
570         refuseFurtherComments();
571         this.isEarthTides = EarthTides;
572     }
573 
574     /**
575      * Get Enum YesNoUnknown that indicates if intrack thrust modeling was into account or not.
576      * @return isEarthTides YesNoUnknown
577      */
578     public YesNoUnknown getIntrackThrust() {
579         return isIntrackThrustModeled;
580     }
581 
582     /**
583      * Set boolean that indicates if intrack thrust modeling was into account or not.
584      * @param IntrackThrustModeled YesNoUnknown
585      */
586     public void setIntrackThrust(final YesNoUnknown IntrackThrustModeled) {
587         refuseFurtherComments();
588         this.isIntrackThrustModeled = IntrackThrustModeled;
589     }
590 
591     /** Get the source of the covariance data.
592      * @return the covarianceSource
593      */
594     public String getCovarianceSource() {
595         return covarianceSource;
596     }
597 
598     /** Set the source of the covariance data.
599      * @param covarianceSource the covarianceSource to set
600      */
601     public void setCovarianceSource(final String covarianceSource) {
602         refuseFurtherComments();
603         this.covarianceSource = covarianceSource;
604     }
605 
606     /** Get the flag indicating the type of alternate covariance information provided.
607      * @return the altCovType
608      */
609     public AltCovarianceType getAltCovType() {
610         return altCovType;
611     }
612 
613     /** Set the flag indicating the type of alternate covariance information provided.
614      * @param altCovType the altCovType to set
615      */
616     public void setAltCovType(final AltCovarianceType altCovType) {
617         refuseFurtherComments();
618         this.altCovType = altCovType;
619     }
620 
621      /**
622      * Get the value of {@code ALT_COV_REF_FRAME} as an Orekit {@link Frame}.
623      * @return the reference frame
624      */
625     public FrameFacade getAltCovRefFrame() {
626         return altCovRefFrame;
627     }
628 
629     /**
630      * Set the name of the reference frame in which the alternate covariance data are given.
631      * @param altCovRefFrame alternate covariance reference frame
632      */
633     public void setAltCovRefFrame(final FrameFacade altCovRefFrame) {
634         refuseFurtherComments();
635 
636         if (getAltCovType() == null) {
637             throw new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD, CdmMetadataKey.ALT_COV_TYPE);
638         }
639 
640         if (altCovRefFrame.asFrame() == null) {
641             throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, altCovRefFrame.getName());
642         }
643 
644         // Only set the frame if within the allowed options: GCRF, EME2000, ITRF
645         if ( altCovRefFrame.asCelestialBodyFrame() == CelestialBodyFrame.GCRF ||
646                  altCovRefFrame.asCelestialBodyFrame() == CelestialBodyFrame.EME2000 ||
647                      altCovRefFrame.asCelestialBodyFrame().name().contains("ITRF") ) {
648             this.altCovRefFrame = altCovRefFrame;
649         } else {
650             throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, altCovRefFrame.getName());
651         }
652     }
653 
654     /** Get the unique identifier of Orbit Data Message(s) that are linked (relevant) to this Conjunction Data Message.
655      * @return the odmMsgLink
656      */
657     public String getOdmMsgLink() {
658         return odmMsgLink;
659     }
660 
661     /** Set the unique identifier of Orbit Data Message(s) that are linked (relevant) to this Conjunction Data Message.
662      * @param odmMsgLink the odmMsgLink to set
663      */
664     public void setOdmMsgLink(final String odmMsgLink) {
665         refuseFurtherComments();
666         this.odmMsgLink = odmMsgLink;
667     }
668 
669     /** Get the unique identifier of Attitude Data Message(s) that are linked (relevant) to this Conjunction Data Message.
670      * @return the admMsgLink
671      */
672     public String getAdmMsgLink() {
673         return admMsgLink;
674     }
675 
676     /** Set the unique identifier of Attitude Data Message(s) that are linked (relevant) to this Conjunction Data Message.
677      * @param admMsgLink the admMsgLink to set
678      */
679     public void setAdmMsgLink(final String admMsgLink) {
680         refuseFurtherComments();
681         this.admMsgLink = admMsgLink;
682     }
683 
684     /** Get the flag indicating whether new tracking observations are anticipated prior to the issue of the next CDM associated with the event
685      * specified by CONJUNCTION_ID.
686      * @return the obsBeforeNextMessage
687      */
688     public YesNoUnknown getObsBeforeNextMessage() {
689         return obsBeforeNextMessage;
690     }
691 
692     /** Set the flag indicating whether new tracking observations are anticipated prior to the issue of the next CDM associated with the event
693      * specified by CONJUNCTION_ID.
694      * @param obsBeforeNextMessage the obsBeforeNextMessage to set
695      */
696     public void setObsBeforeNextMessage(final YesNoUnknown obsBeforeNextMessage) {
697         refuseFurtherComments();
698         this.obsBeforeNextMessage = obsBeforeNextMessage;
699     }
700 }