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.hipparchus.geometry.euclidean.threed.Vector3D;
24  import org.orekit.annotation.Nullable;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.files.ccsds.definitions.PocMethodFacade;
28  import org.orekit.files.ccsds.definitions.TimeSystem;
29  import org.orekit.time.AbsoluteDate;
30  
31  /** This class gathers the relative meta-data present in the Conjunction Data Message (CDM).
32   * @author Melina Vanel
33   * @since 11.2
34   */
35  public class CdmRelativeMetadata {
36  
37      /** Time System: used for metadata, orbit state and covariance data. */
38      private TimeSystem timeSystem;
39  
40      /** Comment. */
41      private final List<String> comment;
42  
43      /** Date and time in UTC of the closest approach. */
44      private AbsoluteDate tca;
45  
46      /** Norm of relative position vector at TCA. */
47      private double missDistance;
48  
49      /** Norm of relative velocity vector at TCA. */
50      @Nullable
51      private Double relativeSpeed;
52  
53      /** The length of the relative position vector, normalized to one-sigma dispersions of the combined error covariance
54       * in the direction of the relative position vector. */
55      @Nullable
56      private Double mahalanobisDistance;
57  
58      /** The R component of Object2's position relative to Object1's position in the Radial/Transverse/Normal coordinate frame. */
59      @Nullable
60      private Double relativePositionR;
61  
62      /** The T component of Object2's position relative to Object1's position in the Radial/Transverse/Normal coordinate frame. */
63      @Nullable
64      private Double relativePositionT;
65  
66      /** The N component of Object2's position relative to Object1's position in the Radial/Transverse/Normal coordinate frame. */
67      @Nullable
68      private Double relativePositionN;
69  
70      /** The R component of Object2's velocity relative to Object1's veloity in the Radial/Transverse/Normal coordinate frame. */
71      @Nullable
72      private Double relativeVelocityR;
73  
74      /** The T component of Object2's velocity relative to Object1's veloity in the Radial/Transverse/Normal coordinate frame. */
75      @Nullable
76      private Double relativeVelocityT;
77  
78      /** The N component of Object2's velocity relative to Object1's veloity in the Radial/Transverse/Normal coordinate frame. */
79      @Nullable
80      private Double relativeVelocityN;
81  
82      /** The start time in UTC of the screening period for the conjunction assessment. */
83      @Nullable
84      private AbsoluteDate startScreenPeriod;
85  
86      /** The stop time in UTC of the screening period for the conjunction assessment. */
87      @Nullable
88      private AbsoluteDate stopScreenPeriod;
89  
90      /** Shape of the screening volume. */
91      @Nullable
92      private ScreenVolumeShape screenVolumeShape;
93  
94      /** Radius of the screening volume. */
95      @Nullable
96      private Double screenVolumeRadius;
97  
98      /** Name of the Object1 centered reference frame in which the screening volume data are given. */
99      @Nullable
100     private ScreenVolumeFrame screenVolumeFrame;
101 
102     /** The R or T (depending on if RTN or TVN is selected) component size of the screening volume in the SCREEN_VOLUME_FRAME. */
103     @Nullable
104     private Double screenVolumeX;
105 
106     /** The T or V (depending on if RTN or TVN is selected) component size of the screening volume in the SCREEN_VOLUME_FRAME. */
107     @Nullable
108     private Double screenVolumeY;
109 
110     /** The N component size of the screening volume in the SCREEN_VOLUME_FRAME. */
111     @Nullable
112     private Double screenVolumeZ;
113 
114     /** The time in UTC when Object2 enters the screening volume. */
115     @Nullable
116     private AbsoluteDate screenEntryTime;
117 
118     /** The time in UTC when Object2 exits the screening volume. */
119     @Nullable
120     private AbsoluteDate screenExitTime;
121 
122     /** The probability (denoted 'p' where 0.0<=p<=1.0), that Object1 and Object2 will collide. */
123     @Nullable
124     private Double collisionProbability;
125 
126     /** The method that was used to calculate the collision probability. */
127     @Nullable
128     private PocMethodFacade collisionProbabilityMethod;
129 
130     /** the Originator's ID that uniquely identifies the conjunction to which the message refers. */
131     @Nullable
132     private String conjunctionId;
133 
134     /** The approach angle computed between Objects 1 and 2 in the RTN coordinate frame relative to object 1. */
135     @Nullable
136     private Double approachAngle;
137 
138     /** The type of screening to be used. */
139     @Nullable
140     private ScreenType screenType;
141 
142     /** The maximum collision probability that Object1 and Object2 will collide. */
143     @Nullable
144     private Double maxCollisionProbability;
145 
146     /** The method that was used to calculate the maximum collision probability. */
147     @Nullable
148     private PocMethodFacade maxCollisionProbabilityMethod;
149 
150     /**  The space environment fragmentation impact (SEFI) adjusted estimate of collision probability that Object1 and Object2 will collide. */
151     @Nullable
152     private Double sefiCollisionProbability;
153 
154     /** The method that was used to calculate the space environment fragmentation impact collision probability. */
155     @Nullable
156     private PocMethodFacade sefiCollisionProbabilityMethod;
157 
158     /** The Space environment fragmentation model used. */
159     @Nullable
160     private String sefiFragmentationModel;
161 
162     /** The collision probability screening threshold used to identify this conjunction. */
163     @Nullable
164     private Double screenPcThreshold;
165 
166     /** An array of 1 to n elements indicating the percentile(s) for which estimates of the collision probability are provided in the
167      * COLLISION_PROBABILITY variable. */
168     @Nullable
169     private int[] collisionPercentile;
170 
171     /** ID of previous CDM issued for event identified by CONJUNCTION_ID. */
172     @Nullable
173     private String previousMessageId;
174 
175     /** UTC epoch of the previous CDM issued for the event identified by CONJUNCTION_ID. */
176     @Nullable
177     private AbsoluteDate previousMessageEpoch;
178 
179     /** Scheduled UTC epoch of the next CDM associated with the event identified by CONJUNCTION_ID. */
180     @Nullable
181     private AbsoluteDate nextMessageEpoch;
182 
183     /** Simple constructor.
184      */
185     public CdmRelativeMetadata() {
186         this.comment = new ArrayList<>();
187     }
188 
189     /** Check is all mandatory entries have been initialized.
190     */
191     public void validate() {
192         checkNotNull(tca,            CdmRelativeMetadataKey.TCA);
193         checkNotNull(missDistance,   CdmRelativeMetadataKey.MISS_DISTANCE);
194         checkScreenVolumeConditions();
195     }
196 
197     /**
198      * Get the Originator's ID that uniquely identifies the conjunction to which the message refers.
199      * @return the conjunction id
200      */
201     public Optional<String> getConjunctionId() {
202         return Optional.ofNullable(conjunctionId);
203     }
204 
205     /**
206      * Set the Originator's ID that uniquely identifies the conjunction to which the message refers.
207      * @param conjunctionId the conjunction id to be set
208      */
209     public void setConjunctionId(final String conjunctionId) {
210         this.conjunctionId = conjunctionId;
211     }
212 
213     /**
214      * Get the date and time in UTC of the closest approach.
215      * @return time of closest approach
216      */
217     public AbsoluteDate getTca() {
218         return tca;
219     }
220 
221     /**
222      * Set the date and time in UTC of the closest approach.
223      * @param tca time of closest approach to be set
224      */
225     public void setTca(final AbsoluteDate tca) {
226         this.tca = tca;
227     }
228 
229     /**
230      * Get the norm of relative position vector at TCA.
231      * @return the miss distance (in m)
232      */
233     public double getMissDistance() {
234         return missDistance;
235     }
236 
237     /**
238      * Set the norm of relative position vector at TCA.
239      * @param missDistance the miss distance to be set (in m)
240      */
241     public void setMissDistance(final double missDistance) {
242         this.missDistance = missDistance;
243     }
244 
245     /**
246      * Get the norm of relative velocity vector at TCA.
247      * @return the relative speed at TCA (in m/s)
248      */
249     public Optional<Double> getRelativeSpeed() {
250         return Optional.ofNullable(relativeSpeed);
251     }
252 
253     /**
254      * Set the norm of relative velocity vector at TCA.
255      * @param relativeSpeed the relative speed (in m/s) at TCA to be set
256      */
257     public void setRelativeSpeed(final double relativeSpeed) {
258         this.relativeSpeed = relativeSpeed;
259     }
260 
261     /**
262      * Get the Object2’s velocity vector relative to Object1's at TCA in RTN frame, getX for R component,
263      * getY for T component, getZ for N component.
264      * @return the relative speed vector at TCA (in m/s)
265      */
266     public Optional<Vector3D> getRelativeVelocity() {
267         if (relativeVelocityR == null || relativeVelocityT == null || relativeVelocityN == null) {
268             return Optional.empty();
269         }
270         return Optional.of(new Vector3D(relativeVelocityR, relativeVelocityT, relativeVelocityN));
271     }
272 
273     /**
274      * Get the Object2’s position vector relative to Object1's at TCA in RTN frame, getX for R component,
275      * getY for T component, getZ for N component.
276      * @return the relative position vector at TCA (in m)
277      */
278     public Optional<Vector3D> getRelativePosition() {
279         if (relativePositionR == null || relativePositionT == null || relativePositionN == null) {
280             return Optional.empty();
281         }
282         return Optional.of(new Vector3D(relativePositionR, relativePositionT, relativePositionN));
283     }
284 
285     /**
286      * Set the R component of Object2’s position relative to Object1’s in RTN frame.
287      * @param relativePositionR the R component (in m) of Object2’s position relative to Object1’s
288      */
289     public void setRelativePositionR(final double relativePositionR) {
290         this.relativePositionR = relativePositionR;
291     }
292 
293     /**
294      * Set the T component of Object2’s position relative to Object1’s in RTN frame.
295      * @param relativePositionT the T component (in m) of Object2’s position relative to Object1’s
296      */
297     public void setRelativePositionT(final double relativePositionT) {
298         this.relativePositionT = relativePositionT;
299     }
300 
301     /**
302      * Set the N component of Object2’s position relative to Object1’s in RTN frame.
303      * @param relativePositionN the N component (in m) of Object2’s position relative to Object1’s
304      */
305     public void setRelativePositionN(final double relativePositionN) {
306         this.relativePositionN = relativePositionN;
307     }
308 
309     /**
310      * Set the R component of Object2’s velocity relative to Object1’s in RTN frame.
311      * @param relativeVelocityR the R component (in m/s) of Object2’s velocity relative to Object1’s
312      */
313     public void setRelativeVelocityR(final double relativeVelocityR) {
314         this.relativeVelocityR = relativeVelocityR;
315     }
316 
317     /**
318      * Set the T component of Object2’s velocity relative to Object1’s in RTN frame.
319      * @param relativeVelocityT the T component (in m/s) of Object2’s velocity relative to Object1’s
320      */
321     public void setRelativeVelocityT(final double relativeVelocityT) {
322         this.relativeVelocityT = relativeVelocityT;
323     }
324 
325     /**
326      * Set the N component of Object2’s velocity relative to Object1’s in RTN frame.
327      * @param relativeVelocityN the N component (in m/s) of Object2’s velocity relative to Object1’s
328      */
329     public void setRelativeVelocityN(final double relativeVelocityN) {
330         this.relativeVelocityN = relativeVelocityN;
331     }
332 
333     /**
334      * Get the start time in UTC of the screening period for the conjunction assessment.
335      * @return start time in UTC of the screening period
336      */
337     public Optional<AbsoluteDate> getStartScreenPeriod() {
338         return Optional.ofNullable(startScreenPeriod);
339     }
340 
341     /**
342      * Set the start time in UTC of the screening period for the conjunction assessment.
343      * @param startScreenPeriod start time in UTC of the screening period to be set
344      */
345     public void setStartScreenPeriod(final AbsoluteDate startScreenPeriod) {
346         this.startScreenPeriod = startScreenPeriod;
347     }
348 
349     /**
350      * Get the stop time in UTC of the screening period for the conjunction assessment.
351      * @return stop time in UTC of the screening period
352      */
353     public Optional<AbsoluteDate> getStopScreenPeriod() {
354         return Optional.ofNullable(stopScreenPeriod);
355     }
356 
357     /**
358      * Set the stop time in UTC of the screening period for the conjunction assessment.
359      * @param stopScreenPeriod stop time in UTC of the screening period to be set
360      */
361     public void setStopScreenPeriod(final AbsoluteDate stopScreenPeriod) {
362         this.stopScreenPeriod = stopScreenPeriod;
363     }
364 
365     /**
366      * Get the name of the Object1 centered reference frame in which the screening volume data are given.
367      * @return name of screen volume frame
368      */
369     public Optional<ScreenVolumeFrame> getScreenVolumeFrame() {
370         return Optional.ofNullable(screenVolumeFrame);
371     }
372 
373     /**
374      * Set the name of the Object1 centered reference frame in which the screening volume data are given.
375      * @param screenVolumeFrame name of screen volume frame
376      */
377     public void setScreenVolumeFrame(final ScreenVolumeFrame screenVolumeFrame) {
378         this.screenVolumeFrame = screenVolumeFrame;
379     }
380 
381     /**
382      * Get the shape of the screening volume.
383      * @return shape of the screening volume
384      */
385     public Optional<ScreenVolumeShape> getScreenVolumeShape() {
386         return Optional.ofNullable(screenVolumeShape);
387     }
388 
389     /**
390      * Set the shape of the screening volume.
391      * @param screenVolumeShape shape of the screening volume
392      */
393     public void setScreenVolumeShape(final ScreenVolumeShape screenVolumeShape) {
394         this.screenVolumeShape = screenVolumeShape;
395     }
396 
397     /**
398      * Get the R or T (depending on if RTN or TVN is selected) component size of the screening volume in the corresponding frame.
399      * @return first component size of the screening volume (in m)
400      */
401     public Optional<Double> getScreenVolumeX() {
402         return Optional.ofNullable(screenVolumeX);    }
403 
404     /**
405      * Set the R or T (depending on if RTN or TVN is selected) component size of the screening volume in the corresponding frame.
406      * @param screenVolumeX first component size of the screening volume (in m)
407      */
408     public void setScreenVolumeX(final double screenVolumeX) {
409         this.screenVolumeX = screenVolumeX;
410     }
411 
412     /**
413      * Set the R or T (depending on if RTN or TVN is selected) component size of the screening volume in the corresponding frame.
414      * @param screenVolumeX first component size of the screening volume (in m)
415      */
416     public void setScreenVolumeX(final Double screenVolumeX) {
417         this.screenVolumeX = screenVolumeX;
418     }
419 
420     /**
421      * Get the T or V (depending on if RTN or TVN is selected) component size of the screening volume in the corresponding frame.
422      * @return second component size of the screening volume (in m)
423      */
424     public Optional<Double> getScreenVolumeY() {
425         return Optional.ofNullable(screenVolumeY);
426     }
427 
428     /**
429      * Set the T or V (depending on if RTN or TVN is selected) component size of the screening volume in the corresponding frame.
430      * @param screenVolumeY second component size of the screening volume (in m)
431      */
432     public void setScreenVolumeY(final double screenVolumeY) {
433         this.screenVolumeY = screenVolumeY;
434     }
435 
436     /**
437      * Set the T or V (depending on if RTN or TVN is selected) component size of the screening volume in the corresponding frame.
438      * @param screenVolumeY second component size of the screening volume (in m)
439      */
440     public void setScreenVolumeY(final Double screenVolumeY) {
441         this.screenVolumeY = screenVolumeY;
442     }
443 
444     /**
445      * Get the N component size of the screening volume in the corresponding frame.
446      * @return third component size of the screening volume (in m)
447      */
448     public Optional<Double> getScreenVolumeZ() {
449         return Optional.ofNullable(screenVolumeZ);
450     }
451 
452     /**
453      * Set the N component size of the screening volume in the corresponding frame.
454      * @param screenVolumeZ third component size of the screening volume (in m)
455      */
456     public void setScreenVolumeZ(final double screenVolumeZ) {
457         this.screenVolumeZ = screenVolumeZ;
458     }
459 
460     /**
461      * Set the N component size of the screening volume in the corresponding frame.
462      * @param screenVolumeZ third component size of the screening volume (in m)
463      */
464     public void setScreenVolumeZ(final Double screenVolumeZ) {
465         this.screenVolumeZ = screenVolumeZ;
466     }
467 
468 
469     /**
470      * Get the time in UTC when Object2 enters the screening volume.
471      * @return time in UTC when Object2 enters the screening volume
472      */
473     public Optional<AbsoluteDate> getScreenEntryTime() {
474         return Optional.ofNullable(screenEntryTime);
475     }
476 
477     /**
478      * Set the time in UTC when Object2 enters the screening volume.
479      * @param screenEntryTime time in UTC when Object2 enters the screening volume
480      */
481     public void setScreenEntryTime(final AbsoluteDate screenEntryTime) {
482         this.screenEntryTime = screenEntryTime;
483     }
484 
485     /**
486      * Get the time in UTC when Object2 exits the screening volume.
487      * @return time in UTC when Object2 exits the screening volume
488      */
489     public Optional<AbsoluteDate> getScreenExitTime() {
490         return Optional.ofNullable(screenExitTime);
491     }
492 
493     /**
494      * Set the time in UTC when Object2 exits the screening volume.
495      * @param screenExitTime time in UTC when Object2 exits the screening volume
496      */
497     public void setScreenExitTime(final AbsoluteDate screenExitTime) {
498         this.screenExitTime = screenExitTime;
499     }
500 
501     /**
502      * Get the probability (between 0.0 and 1.0) that Object1 and Object2 will collide.
503      * @return probability of collision
504      */
505     public Optional<Double> getCollisionProbability() {
506         return Optional.ofNullable(collisionProbability);
507     }
508 
509     /**
510      * Set the probability (between 0.0 and 1.0) that Object1 and Object2 will collide.
511      * @param collisionProbability first component size of the screening volume
512      */
513     public void setCollisionProbability(final double collisionProbability) {
514         this.collisionProbability = collisionProbability;
515     }
516 
517     /**
518      * Get the method that was used to calculate the collision probability.
519      * @return method to calculate probability of collision
520      */
521     public Optional<PocMethodFacade> getCollisionProbaMethod() {
522         return Optional.ofNullable(collisionProbabilityMethod);
523     }
524 
525     /**
526      * Set the method that was used to calculate the collision probability.
527      * @param collisionProbaMethod method used to calculate probability of collision
528      */
529     public void setCollisionProbaMethod(final PocMethodFacade collisionProbaMethod) {
530         this.collisionProbabilityMethod = collisionProbaMethod;
531     }
532 
533     /** Complain if a field is null.
534      * @param field field to check
535      * @param key key associated with the field
536      */
537     public void checkNotNull(final Object field, final Enum<?> key) {
538         if (field == null) {
539             throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, key.name());
540         }
541     }
542 
543     /** Set the Time System that: for CDM, is used for relative metadata, metadata,
544      * OD parameters, state vector. In CDM all date are given in UTC.
545      * @param timeSystem the time system to be set
546      */
547     public void setTimeSystem(final TimeSystem timeSystem) {
548         this.timeSystem = timeSystem;
549     }
550 
551     /** Get the Time System that: for CDM, is used for relative metadata, metadata,
552      * OD parameters, state vector. In CDM all date are given in UTC.
553      * @return the time system
554      */
555     public TimeSystem getTimeSystem() {
556         return timeSystem;
557     }
558 
559     /** Set comment for relative metadata.
560      * @param comments to be set
561      */
562     public void addComment(final String comments) {
563         this.comment.add(comments);
564     }
565 
566     /** Get comment for relative metadata.
567      * @return the time system
568      */
569     public List<String> getComment() {
570         return comment;
571     }
572 
573     /** Get the approach angle computed between Objects 1 and 2 in the RTN coordinate frame relative to object 1.
574      * @return the approachAngle
575      */
576     public Optional<Double> getApproachAngle() {
577         return Optional.ofNullable(approachAngle);
578     }
579 
580     /** Set the approach angle computed between Objects 1 and 2 in the RTN coordinate frame relative to object 1.
581      * @param approachAngle the approachAngle to set
582      */
583     public void setApproachAngle(final double approachAngle) {
584         this.approachAngle = approachAngle;
585     }
586 
587     /** Get the type of screening to be used.
588      * @return the screenType
589      */
590     public Optional<ScreenType> getScreenType() {
591         return Optional.ofNullable(screenType);
592     }
593 
594     /** Set the type of screening to be used.
595      * @param screenType the screenType to set
596      */
597     public void setScreenType(final ScreenType screenType) {
598         this.screenType = screenType;
599     }
600 
601     /** Get max collision probability.
602      * @return the max collision probability
603      */
604     public Optional<Double> getMaxCollisionProbability() {
605         return Optional.ofNullable(maxCollisionProbability);
606     }
607 
608     /** Set max collision probability.
609      * @param maxCollisionProbability the max collision probability to set
610      */
611     public void setMaxCollisionProbability(final double maxCollisionProbability) {
612         this.maxCollisionProbability = maxCollisionProbability;
613     }
614 
615     /** Get max collision probability method.
616      * @return the max collision probability method
617      */
618     public Optional<PocMethodFacade> getMaxCollisionProbabilityMethod() {
619         return Optional.ofNullable(maxCollisionProbabilityMethod);
620     }
621 
622     /** Set max collision probability method.
623      * @param pocMethodFacade the max collision probability method to set
624      */
625     public void setMaxCollisionProbabilityMethod(final PocMethodFacade pocMethodFacade) {
626         this.maxCollisionProbabilityMethod = pocMethodFacade;
627     }
628 
629     /** Get the Space Environment Fragmentation Impact probability.
630      * @return the Space Environment Fragmentation Impact probability
631      */
632     public Optional<Double> getSefiCollisionProbability() {
633         return Optional.ofNullable(sefiCollisionProbability);
634     }
635 
636     /** Set the Space Environment Fragmentation Impact probability.
637      * @param sefiCollisionProbability the Space Environment Fragmentation Impact probability to set
638      */
639     public void setSefiCollisionProbability(final double sefiCollisionProbability) {
640         this.sefiCollisionProbability = sefiCollisionProbability;
641     }
642 
643     /** Get the Space Environment Fragmentation Impact probability method.
644      * @return the Space Environment Fragmentation Impact probability method
645      */
646     public Optional<PocMethodFacade> getSefiCollisionProbabilityMethod() {
647         return Optional.ofNullable(sefiCollisionProbabilityMethod);
648     }
649 
650     /** Set the Space Environment Fragmentation Impact probability method.
651      * @param pocMethodFacade the Space Environment Fragmentation Impact probability method to set
652      */
653     public void setSefiCollisionProbabilityMethod(final PocMethodFacade pocMethodFacade) {
654         this.sefiCollisionProbabilityMethod = pocMethodFacade;
655     }
656 
657     /** Get the Space Environment Fragmentation Impact fragmentation model.
658      * @return the Space Environment Fragmentation Impact fragmentation model
659      */
660     public Optional<String> getSefiFragmentationModel() {
661         return Optional.ofNullable(sefiFragmentationModel);
662     }
663 
664     /** Set the Space Environment Fragmentation Impact fragmentation model.
665      * @param sefiFragmentationModel the Space Environment Fragmentation Impact fragmentation model to set
666      */
667     public void setSefiFragmentationModel(final String sefiFragmentationModel) {
668         this.sefiFragmentationModel = sefiFragmentationModel;
669     }
670 
671     /** Get the Mahalanobis Distance. The length of the relative position vector, normalized to one-sigma dispersions of the combined error covariance
672      * in the direction of the relative position vector.
673      * @return the mahalanobisDistance
674      */
675     public Optional<Double> getMahalanobisDistance() {
676         return Optional.ofNullable(mahalanobisDistance);
677     }
678 
679     /** Set the Mahalanobis Distance. The length of the relative position vector, normalized to one-sigma dispersions of the combined error covariance
680      * in the direction of the relative position vector.
681      * @param mahalanobisDistance the mahalanobisDistance to set
682      */
683     public void setMahalanobisDistance(final double mahalanobisDistance) {
684         this.mahalanobisDistance = mahalanobisDistance;
685     }
686 
687     /** Get the screen volume radius.
688      * @return the screen volume radius
689      */
690     public Optional<Double> getScreenVolumeRadius() {
691         return Optional.ofNullable(screenVolumeRadius);
692     }
693 
694     /** set the screen volume radius.
695      * @param screenVolumeRadius the screen volume radius to set
696      */
697     public void setScreenVolumeRadius(final double screenVolumeRadius) {
698         this.screenVolumeRadius = screenVolumeRadius;
699     }
700 
701     /** Get the collision probability screening threshold used to identify this conjunction.
702     * @return the screenPcThreshold
703     */
704     public Optional<Double> getScreenPcThreshold() {
705         return Optional.ofNullable(screenPcThreshold);
706     }
707 
708     /** Set the collision probability screening threshold used to identify this conjunction.
709     * @param screenPcThreshold the screenPcThreshold to set
710     */
711     public void setScreenPcThreshold(final double screenPcThreshold) {
712         this.screenPcThreshold = screenPcThreshold;
713     }
714 
715     /**
716      * Check screen volume conditions.
717      * <p>
718      * The method verifies that all keys are present.
719      * Otherwise, an exception is thrown.
720      * </p>
721      */
722     public void checkScreenVolumeConditions() {
723 
724         if (this.getScreenType().isPresent() &&  this.getScreenType().get() == ScreenType.SHAPE) {
725 
726             getScreenEntryTime().
727                 orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
728                                                       CdmRelativeMetadataKey.SCREEN_ENTRY_TIME));
729 
730             getScreenExitTime().
731                 orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
732                                                       CdmRelativeMetadataKey.SCREEN_EXIT_TIME));
733 
734             getScreenVolumeShape().
735                 orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
736                                                       CdmRelativeMetadataKey.SCREEN_VOLUME_SHAPE));
737 
738             if (this.getScreenVolumeShape().isPresent() && this.getScreenVolumeShape().get() == ScreenVolumeShape.SPHERE) {
739 
740                 getScreenVolumeRadius().
741                     orElseThrow(() ->  new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
742                                                            CdmRelativeMetadataKey.SCREEN_VOLUME_RADIUS));
743 
744             } else if (this.getScreenVolumeShape().isPresent() && (this.getScreenVolumeShape().get() == ScreenVolumeShape.ELLIPSOID ||
745                     this.getScreenVolumeShape().get() == ScreenVolumeShape.BOX)) {
746 
747                 getScreenVolumeFrame().
748                     orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
749                                                           CdmRelativeMetadataKey.SCREEN_VOLUME_FRAME));
750                 getScreenVolumeX().
751                     orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
752                                                           CdmRelativeMetadataKey.SCREEN_VOLUME_X));
753                 getScreenVolumeY().
754                     orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
755                                                           CdmRelativeMetadataKey.SCREEN_VOLUME_Y));
756                 getScreenVolumeZ().
757                     orElseThrow(() -> new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD,
758                                                           CdmRelativeMetadataKey.SCREEN_VOLUME_Z));
759             }
760 
761         } else if (this.getScreenType().isPresent() &&
762                    (this.getScreenType().get() == ScreenType.PC || this.getScreenType().get() == ScreenType.PC_MAX)) {
763 
764             if (this.getScreenPcThreshold().isEmpty()) {
765                 throw new OrekitException(OrekitMessages.CCSDS_MISSING_KEYWORD, CdmRelativeMetadataKey.SCREEN_PC_THRESHOLD);
766             }
767         }
768 
769     }
770 
771     /** Get the array of 1 to n elements indicating the percentile(s) for which estimates of the collision probability are provided in the
772      * COLLISION_PROBABILITY variable.
773      * @return the collisionPercentile
774      */
775     public Optional<int[]> getCollisionPercentile() {
776         return collisionPercentile == null ? Optional.empty() : Optional.ofNullable(collisionPercentile.clone());
777     }
778 
779     /** Set the array of 1 to n elements indicating the percentile(s) for which estimates of the collision probability are provided in the
780      * COLLISION_PROBABILITY variable.
781      * @param collisionPercentile the collisionPercentile to set
782      */
783     public void setCollisionPercentile(final int[] collisionPercentile) {
784         this.collisionPercentile = collisionPercentile == null ? null : collisionPercentile.clone();
785     }
786 
787     /** Get the ID of previous CDM issued for event identified by CONJUNCTION_ID.
788      * @return the previousMessageId
789      */
790     public Optional<String> getPreviousMessageId() {
791         return Optional.ofNullable(previousMessageId);
792     }
793 
794     /** Set the ID of previous CDM issued for event identified by CONJUNCTION_ID.
795      * @param previousMessageId the previousMessageId to set
796      */
797     public void setPreviousMessageId(final String previousMessageId) {
798         this.previousMessageId = previousMessageId;
799     }
800 
801     /** Get the UTC epoch of the previous CDM issued for the event identified by CONJUNCTION_ID.
802      * @return the previousMessageEpoch
803      */
804     public Optional<AbsoluteDate> getPreviousMessageEpoch() {
805         return Optional.ofNullable(previousMessageEpoch);
806     }
807 
808     /** Set the UTC epoch of the previous CDM issued for the event identified by CONJUNCTION_ID.
809      * @param previousMessageEpoch the previousMessageEpoch to set
810      */
811     public void setPreviousMessageEpoch(final AbsoluteDate previousMessageEpoch) {
812         this.previousMessageEpoch = previousMessageEpoch;
813     }
814 
815     /** Get Scheduled UTC epoch of the next CDM associated with the event identified by CONJUNCTION_ID.
816      * @return the nextMessageEpoch
817      */
818     public Optional<AbsoluteDate> getNextMessageEpoch() {
819         return Optional.ofNullable(nextMessageEpoch);
820     }
821 
822     /** Set Scheduled UTC epoch of the next CDM associated with the event identified by CONJUNCTION_ID.
823      * @param nextMessageEpoch the nextMessageEpoch to set
824      */
825     public void setNextMessageEpoch(final AbsoluteDate nextMessageEpoch) {
826         this.nextMessageEpoch = nextMessageEpoch;
827     }
828 }