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